blob: 2c867e1d7f7726b5f821440cbec7cdf9e96085bc [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 by SAP AG, Walldorf.
* 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:
* SAP AG - initial API and implementation
*******************************************************************************/
package org.eclipse.jst.ws.jaxws.utils.internal.annotations.impl;
import static org.eclipse.jst.ws.jaxws.utils.ContractChecker.nullCheckParam;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IImportDeclaration;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeParameter;
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.Annotation;
import org.eclipse.jdt.core.dom.ArrayInitializer;
import org.eclipse.jdt.core.dom.BodyDeclaration;
import org.eclipse.jdt.core.dom.BooleanLiteral;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.IExtendedModifier;
import org.eclipse.jdt.core.dom.MarkerAnnotation;
import org.eclipse.jdt.core.dom.MemberValuePair;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.NumberLiteral;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.QualifiedType;
import org.eclipse.jdt.core.dom.SimpleType;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.TypeLiteral;
import org.eclipse.jst.ws.jaxws.utils.ContractChecker;
import org.eclipse.jst.ws.jaxws.utils.annotations.AnnotationFactory;
import org.eclipse.jst.ws.jaxws.utils.annotations.IAnnotation;
import org.eclipse.jst.ws.jaxws.utils.annotations.IAnnotationInspector;
import org.eclipse.jst.ws.jaxws.utils.annotations.ILocator;
import org.eclipse.jst.ws.jaxws.utils.annotations.IParamValuePair;
import org.eclipse.jst.ws.jaxws.utils.annotations.IValue;
import org.eclipse.jst.ws.jaxws.utils.clazz.ASTUtils;
/**
* Class, which is made to load and return annotations from a given IJavaElemet.
*
* @author Plamen Pavlov
*/
public class AnnotationInspectorImpl implements IAnnotationInspector
{
private IType iType;
private CompilationUnit cUnit;
public AnnotationInspectorImpl(final IType type)
{
ContractChecker.nullCheckParam(type, "type"); //$NON-NLS-1$
this.iType = type;
}
public IAnnotation<IMethod> inspectMethod(final IMethod method, final String annotationQName) throws JavaModelException
{
ContractChecker.nullCheckParam(method, "method"); //$NON-NLS-1$
ContractChecker.nullCheckParam(annotationQName, "annotationQName"); //$NON-NLS-1$
if(!(method instanceof IMethod))
{
throw new IllegalArgumentException("method argument is not of correct Type!"); //$NON-NLS-1$
}
if(annotationQName.trim().equals("")) //$NON-NLS-1$
{
throw new IllegalArgumentException("annotationQName argument is not with propper value!"); //$NON-NLS-1$
}
return getSpecificAnnotationFromMember(method, method.getParent().getElementName(), annotationQName);
}
public Collection<IAnnotation<IMethod>> inspectMethod(IMethod method) throws JavaModelException
{
ContractChecker.nullCheckParam(method, "method"); //$NON-NLS-1$
if(!(method instanceof IMethod))
{
throw new IllegalArgumentException("method argument is not of correct Type!"); //$NON-NLS-1$
}
return getFromMember(method, method.getParent().getElementName());
}
public IAnnotation<IField> inspectField(final IField field, final String annotationQName) throws JavaModelException
{
nullCheckParam(field, "field"); //$NON-NLS-1$
nullCheckParam(annotationQName, "annotationQName"); //$NON-NLS-1$
if(!(field instanceof IField))
{
throw new IllegalArgumentException("field argument is not of correct Type!"); //$NON-NLS-1$
}
if(annotationQName.trim().equals("")) //$NON-NLS-1$
{
throw new IllegalArgumentException("annotationQName argument is not with propper value!"); //$NON-NLS-1$
}
final String className = field.getParent().getElementName();
return getSpecificAnnotationFromMember(field, className, annotationQName);
}
public Collection<IAnnotation<IField>> inspectField(IField field) throws JavaModelException
{
if (field == null)
{
throw new NullPointerException("field should not be null!"); //$NON-NLS-1$
}
if(!(field instanceof IField))
{
throw new IllegalArgumentException("field argument is not of correct Type!"); //$NON-NLS-1$
}
final String className = field.getParent().getElementName();
return getFromMember(field, className);
}
public IAnnotation<ITypeParameter> inspectParam(final ITypeParameter param, final String annotationQName) throws JavaModelException
{
nullCheckParam(param, "param"); //$NON-NLS-1$
nullCheckParam(annotationQName, "annotationQName"); //$NON-NLS-1$
if(!(param instanceof ITypeParameter))
{
throw new IllegalArgumentException("param argument is not of correct Type!"); //$NON-NLS-1$
}
if(annotationQName.trim().equals("")) //$NON-NLS-1$
{
throw new IllegalArgumentException("annotationQName argument is not with propper value!"); //$NON-NLS-1$
}
final String className = getClassNameFromParam(param);
return getSpecificAnnotationFromMember(param, className, annotationQName);
}
public Collection<IAnnotation<ITypeParameter>> inspectParam(ITypeParameter param) throws JavaModelException
{
if (param == null)
{
throw new NullPointerException("param should not be null!"); //$NON-NLS-1$
}
if(!(param instanceof ITypeParameter))
{
throw new IllegalArgumentException("param argument is not of correct Type!"); //$NON-NLS-1$
}
return getFromMember(param, getClassNameFromParam(param));
}
public IAnnotation<IType> inspectType(final String annotationQName) throws JavaModelException
{
nullCheckParam(annotationQName, "annotationQName"); //$NON-NLS-1$
if (annotationQName.trim().equals("")) //$NON-NLS-1$
{
throw new IllegalArgumentException("annotationQName argument is not with propper value!"); //$NON-NLS-1$
}
return getSpecificAnnotationFromMember(iType, iType.getElementName(), annotationQName);
}
public Collection<IAnnotation<IType>> inspectType() throws JavaModelException
{
return getFromMember(iType, iType.getElementName());
}
// # implementation
private String getClassNameFromParam(final ITypeParameter param) throws JavaModelException
{
if(param.getDeclaringMember() instanceof IMethod)
{
return param.getDeclaringMember().getParent().getElementName();
}
return param.getDeclaringMember().getElementName();
}
protected <T extends IJavaElement> Set<IAnnotation<T>> getFromMember(T type, String className) throws JavaModelException
{
if (!isSupportedJavaElement(type)) {
throw new IllegalArgumentException("passed argument is not of correct type."); //$NON-NLS-1$
}
ICompilationUnit cUnit = null;
if(type instanceof IMember) {
cUnit = ((IMember)type).getCompilationUnit();
}
else {
cUnit = ((ITypeParameter)type).getDeclaringMember().getCompilationUnit();
}
if (cUnit == null) {
return new HashSet<IAnnotation<T>>();
}
final CompilationUnit unit = getCompilationUnit();
final AbstractTypeDeclaration typeDeclaration = ASTUtils.getInstance().getTypeDeclaration(className, unit);
switch(type.getElementType())
{
case IJavaElement.TYPE:
return getAnnotations(type, typeDeclaration);
case IJavaElement.FIELD:
FieldDeclaration fieldDeclaration = ASTUtils.getInstance().getFieldDeclaration((IField) type, (TypeDeclaration)typeDeclaration);
return getAnnotations(type, fieldDeclaration);
case IJavaElement.METHOD:
MethodDeclaration methodDeclaration = ASTUtils.getInstance().getMethodDeclaration((IMethod) type, (TypeDeclaration)typeDeclaration);
return getAnnotations(type, methodDeclaration);
case IJavaElement.TYPE_PARAMETER:
methodDeclaration = ASTUtils.getInstance().getMethodDeclaration((IMethod)((ITypeParameter) type).getParent(), (TypeDeclaration)typeDeclaration);
return getParamAnnotations(type, methodDeclaration);
}
return new HashSet<IAnnotation<T>>();
}
@SuppressWarnings("unchecked")
private <T extends IJavaElement> Set<IAnnotation<T>> getAnnotations(T iMember, BodyDeclaration bodyDeclaration) throws JavaModelException
{
if (bodyDeclaration != null)
{
List list = bodyDeclaration.modifiers();
return extractAnnotations(iMember, list);
}
return new HashSet<IAnnotation<T>>();
}
@SuppressWarnings("unchecked")
private <T extends IJavaElement> Set<IAnnotation<T>> getParamAnnotations(T iMember, MethodDeclaration methodDeclaration) throws JavaModelException
{
if (methodDeclaration != null)
{
for (Object param : methodDeclaration.parameters())
{
if (param instanceof SingleVariableDeclaration &&
((ITypeParameter)iMember).getElementName().toString().equals(((SingleVariableDeclaration)param).getName().toString()))
{
List list = ((SingleVariableDeclaration) param).modifiers();
return extractAnnotations(iMember, list);
}
}
}
return new HashSet<IAnnotation<T>>();
}
@SuppressWarnings("unchecked")
private <T extends IJavaElement> Set<IAnnotation<T>> extractAnnotations(T iMember, List list) throws JavaModelException
{
Iterator iter = list.iterator();
Set<IValue> values = new HashSet<IValue>();
while (iter.hasNext())
{
IExtendedModifier element = (IExtendedModifier) iter.next();
if (element.isAnnotation())
{
values.add(convertExpression((Expression) element));
}
}
Set<IAnnotation<T>> expressions = new HashSet<IAnnotation<T>>();
for (IValue value : values)
{
AnnotationImpl<T> ann = (AnnotationImpl<T>)value;
ann.setAppliedElementWithoutSave(iMember);
expressions.add(ann);
}
return expressions;
}
@SuppressWarnings("unchecked")
private <T extends IJavaElement> IAnnotation<T> extractSpecificAnnotation(T iMember, List list, IType type, String annotationQName) throws JavaModelException
{
Iterator iter = list.iterator();
Set<IValue> values = new HashSet<IValue>();
while (iter.hasNext())
{
IExtendedModifier element = (IExtendedModifier) iter.next();
if (element.isAnnotation())
{
final Name typeName = ((Annotation)element).getTypeName();
if (annotationQName.endsWith(typeName.getFullyQualifiedName())) {
values.add(convertExpression((Expression) element));
}
}
}
for (IValue value : values)
{
AnnotationImpl<T> tmpAnnotation = (AnnotationImpl<T>)value;
if(checkSpecificAnnotattion(tmpAnnotation, type, annotationQName))
{
AnnotationImpl<T> result = new AnnotationImpl<T>(annotationQName, tmpAnnotation.getParamValuePairs());
result.setAppliedElementWithoutSave(iMember);
result.setLocator(tmpAnnotation.getLocator());
return result;
}
}
return null;
}
private <T extends IJavaElement> boolean checkSpecificAnnotattion(final AnnotationImpl<T> annotation, final IType type, final String annotationQName) throws JavaModelException
{
if(annotation.getAnnotationName().equals(annotationQName) ||
(type.getPackageFragment().getElementName() + "." + annotation.getAnnotationName()).equals(annotationQName)) //$NON-NLS-1$
{
return true;
}
ICompilationUnit cUnit = type.getCompilationUnit();
IImportDeclaration[] imports = cUnit.getImports();
for (IImportDeclaration importDeclaration : imports)
{
if(annotationQName.endsWith(annotation.getAnnotationName()) && importDeclaration.getElementName().equals(annotationQName))
{
return true;
}
}
for (IImportDeclaration importDeclaration : imports)
{
if(importDeclaration.getElementName().endsWith("*")) //$NON-NLS-1$
{
String importStr = importDeclaration.getElementName().substring(0, importDeclaration.getElementName().length() - 1);
if(annotationQName.endsWith(annotation.getAnnotationName()) && annotationQName.indexOf(importStr) == 0)
{
return true;
}
}
}
return false;
}
@SuppressWarnings("unchecked")
private IValue convertExpression(Expression element) throws JavaModelException
{
switch (element.getNodeType())
{
case ASTNode.MARKER_ANNOTATION:
{
MarkerAnnotation ma = (MarkerAnnotation) element;
AnnotationImpl annotation = new AnnotationImpl(getFullyQualifiedAnnotationName(ma), new HashSet<IParamValuePair>());
annotation.setLocator(createLocator(ma));
return annotation;
}
case ASTNode.SINGLE_MEMBER_ANNOTATION:
{
final SingleMemberAnnotation sma = (SingleMemberAnnotation) element;
final Set<IParamValuePair> values = new HashSet<IParamValuePair>();
final IValue value = convertExpression(sma.getValue());
if (value!=null) {
values.add(AnnotationFactory.createParamValuePairValue("value", value)); //$NON-NLS-1$
}
AnnotationImpl annotation = new AnnotationImpl(getFullyQualifiedAnnotationName(sma), values);
annotation.setLocator(createLocator(sma));
return annotation;
}
case ASTNode.NORMAL_ANNOTATION:
{
return getNormalAnnotationValue((NormalAnnotation) element);
}
case ASTNode.ARRAY_INITIALIZER:
{
ArrayInitializer arr = (ArrayInitializer) element;
List<Expression> list = arr.expressions();
Iterator<Expression> iter = list.iterator();
Set<IValue> result = new HashSet<IValue>();
while (iter.hasNext())
{
Expression expr = (Expression) iter.next();
result.add(convertExpression(expr));
}
return new ArrayValueImpl(result);
}
case ASTNode.NULL_LITERAL:
{
// return AnnotationFactory.createNullValue();
break;
}
case ASTNode.SIMPLE_NAME:
{
break;//return new StringValueImpl(((SimpleName)element).getIdentifier());
}
case ASTNode.TYPE_LITERAL:
{
return getTypeLiteralValue((TypeLiteral) element);
}
case ASTNode.QUALIFIED_NAME:
{
QualifiedName qn = (QualifiedName) element;
QualifiedNameValueImpl qnValue = new QualifiedNameValueImpl(qn.getFullyQualifiedName());
qnValue.setLocator(createLocator(qn));
return qnValue;
}
case ASTNode.BOOLEAN_LITERAL:
{
BooleanLiteral bl = (BooleanLiteral) element;
BooleanValueImpl bValue = new BooleanValueImpl(bl.booleanValue());
bValue.setLocator(createLocator(bl));
return bValue;
}
case ASTNode.CHARACTER_LITERAL:
{
// CharacterLiteral cl = (CharacterLiteral) element;
// TODO Finish with this return new CharacterValue(cl.charValue());
break;
}
case ASTNode.NUMBER_LITERAL:
{
NumberLiteral nl = (NumberLiteral) element;
IntegerValueImpl intValue = new IntegerValueImpl(nl.getToken());
intValue.setLocator(createLocator(nl));
return intValue;
}
case ASTNode.STRING_LITERAL:
{
StringLiteral sl = (StringLiteral) element;
StringValueImpl strValue = new StringValueImpl(sl.getLiteralValue());
strValue.setLocator(createLocator(sl));
return strValue;
}
}
return null;
}
private IValue getTypeLiteralValue(TypeLiteral tl) throws JavaModelException
{
Type type = tl.getType();
Name name = null;
if (type.isQualifiedType())
{
name = ((QualifiedType) type).getName();
} else
{
if (type.isSimpleType())
{
name = ((SimpleType) type).getName();
}
}
if (name != null)
{
CompilationUnit cu = getCompilationUnit(tl);
if (cu != null)
{
String fullyQualifiedName = name.getFullyQualifiedName();
if (type.isSimpleType())
{
fullyQualifiedName = resolveType((ICompilationUnit) cu.getJavaElement(), fullyQualifiedName);
}
ClassValueImpl cValue = new ClassValueImpl(fullyQualifiedName);
cValue.setLocator(createLocator(tl));
return cValue;
}
}
return null;
}
@SuppressWarnings("unchecked")
private IValue getNormalAnnotationValue(NormalAnnotation na) throws JavaModelException
{
List<MemberValuePair> l = na.values();
Iterator<MemberValuePair> iter = l.iterator();
Set<IParamValuePair> result = new HashSet<IParamValuePair>();
while (iter.hasNext())
{
MemberValuePair mvp = (MemberValuePair) iter.next();
IValue mvpval = convertExpression(mvp.getValue());
ParamValuePairImpl pair = new ParamValuePairImpl(mvp.getName().getIdentifier(), mvpval);
pair.setLocator(createLocator(mvp));
result.add(pair);
}
AnnotationImpl annotation = new AnnotationImpl(getFullyQualifiedAnnotationName(na), result);
annotation.setLocator(createLocator(na));
return annotation;
}
private String getFullyQualifiedAnnotationName(Annotation anno) throws JavaModelException
{
Name typeName = anno.getTypeName();
String fullyQualifiedName = typeName.getFullyQualifiedName();
if (typeName.isSimpleName())
{
CompilationUnit cu = getCompilationUnit(anno);
fullyQualifiedName = resolveType((ICompilationUnit) cu.getJavaElement(), fullyQualifiedName);
}
return fullyQualifiedName;
}
private CompilationUnit getCompilationUnit(Expression element)
{
ASTNode cu = element;
while (cu != null && !(cu instanceof CompilationUnit))
{
cu = cu.getParent();
}
return (CompilationUnit) cu;
}
private String resolveType(ICompilationUnit icu, String fullyQualifiedName) throws JavaModelException
{
String localFullyQualifiedName = fullyQualifiedName;
IType[] allTypes = icu.getAllTypes();
if (allTypes == null)
{
return localFullyQualifiedName;
}
for (int i = 0; i < allTypes.length; i++)
{
String[][] resolvedType = allTypes[i].resolveType(localFullyQualifiedName);
if (resolvedType != null && resolvedType.length > 0)
{
StringBuffer buf = new StringBuffer();
for (int j = 0; j < resolvedType[0].length; j++)
{
buf = appendDot(j, buf);
buf.append(resolvedType[0][j]);
}
localFullyQualifiedName = buf.toString();
break;
}
}
return localFullyQualifiedName;
}
private StringBuffer appendDot(int index, StringBuffer buff)
{
StringBuffer result = buff;
if (index != 0)
{
result.append('.');
}
return result;
}
protected <T extends IJavaElement> IAnnotation<T> getSpecificAnnotationFromMember(final T type, final String className, final String annotationQName) throws JavaModelException
{
if (!isSupportedJavaElement(type))
{
throw new IllegalArgumentException("passed argument is not of correct type."); //$NON-NLS-1$
}
ICompilationUnit cUnit = null;
if (type instanceof IMember) {
cUnit = ((IMember)type).getCompilationUnit();
}
else {
cUnit = ((ITypeParameter)type).getDeclaringMember().getCompilationUnit();
}
if (cUnit == null) {
return null;
}
final CompilationUnit unit = getCompilationUnit();
final AbstractTypeDeclaration typeDeclaration = ASTUtils.getInstance().getTypeDeclaration(className, unit);
switch(type.getElementType())
{
case IJavaElement.TYPE:
return getSpecificAnnotation(type, typeDeclaration, (IType)type, annotationQName);
case IJavaElement.FIELD:
IField field = (IField) type;
FieldDeclaration fieldDeclaration = ASTUtils.getInstance().getFieldDeclaration(field, (TypeDeclaration)typeDeclaration);
return getSpecificAnnotation(type, fieldDeclaration, field.getDeclaringType(), annotationQName);
case IJavaElement.METHOD:
IMethod method = (IMethod) type;
MethodDeclaration methodDeclaration = ASTUtils.getInstance().getMethodDeclaration(method, (TypeDeclaration)typeDeclaration);
return getSpecificAnnotation(type, methodDeclaration, method.getDeclaringType(), annotationQName);
case IJavaElement.TYPE_PARAMETER:
method = (IMethod)((ITypeParameter) type).getParent();
methodDeclaration = ASTUtils.getInstance().getMethodDeclaration(method, (TypeDeclaration)typeDeclaration);
return getSpecificParamAnnotation(type, methodDeclaration, method.getDeclaringType(), annotationQName);
}
return null;
}
private <T extends IJavaElement> IAnnotation<T> getSpecificAnnotation(final T iMember, final BodyDeclaration bodyDeclaration, final IType type, final String annotationQName) throws JavaModelException
{
if (bodyDeclaration != null)
{
@SuppressWarnings("unchecked")
final List list = bodyDeclaration.modifiers();
return extractSpecificAnnotation(iMember, list, type, annotationQName);
}
return null;
}
private <T extends IJavaElement> IAnnotation<T> getSpecificParamAnnotation(T iMember, MethodDeclaration methodDeclaration, final IType type, final String annotationQName) throws JavaModelException
{
if (methodDeclaration != null)
{
for (Object param : methodDeclaration.parameters())
{
if (param instanceof SingleVariableDeclaration &&
((ITypeParameter)iMember).getElementName().toString().equals(((SingleVariableDeclaration)param).getName().toString()))
{
@SuppressWarnings("unchecked")
final List list = ((SingleVariableDeclaration) param).modifiers();
return extractSpecificAnnotation(iMember, list, type, annotationQName);
}
}
}
return null;
}
private boolean isSupportedJavaElement(final IJavaElement javaElement)
{
return javaElement.getElementType()==IJavaElement.METHOD ||
javaElement.getElementType()==IJavaElement.TYPE ||
javaElement.getElementType()==IJavaElement.FIELD ||
javaElement.getElementType()==IJavaElement.TYPE_PARAMETER;
}
private CompilationUnit getCompilationUnit()
{
if (cUnit==null) {
cUnit = ASTUtils.getInstance().createCompilationUnit(iType.getCompilationUnit(), null);
}
return cUnit;
}
private ILocator createLocator(final ASTNode node)
{
final int lineNumber = getCompilationUnit().getLineNumber(node.getStartPosition());
return new LocatorImpl(lineNumber, node.getStartPosition(), node.getLength());
}
}