| /******************************************************************************* |
| * Copyright (c) 2005, 2008 BEA Systems, Inc. |
| * 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: |
| * tyeung@bea.com - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.jdt.apt.core.internal.declaration; |
| |
| import java.util.Collections; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.jdt.apt.core.internal.env.BaseProcessorEnv; |
| import org.eclipse.jdt.apt.core.internal.util.Factory; |
| import org.eclipse.jdt.apt.core.internal.util.SourcePositionImpl; |
| import org.eclipse.jdt.core.dom.ASTNode; |
| import org.eclipse.jdt.core.dom.Annotation; |
| import org.eclipse.jdt.core.dom.CompilationUnit; |
| import org.eclipse.jdt.core.dom.IMethodBinding; |
| import org.eclipse.jdt.core.dom.IAnnotationBinding; |
| import org.eclipse.jdt.core.dom.IMemberValuePairBinding; |
| import org.eclipse.jdt.core.dom.ITypeBinding; |
| import org.eclipse.jdt.core.dom.IVariableBinding; |
| import org.eclipse.jdt.core.dom.MemberValuePair; |
| import org.eclipse.jdt.core.dom.Name; |
| import org.eclipse.jdt.core.dom.NormalAnnotation; |
| import org.eclipse.jdt.core.dom.SingleMemberAnnotation; |
| |
| import com.sun.mirror.declaration.AnnotationMirror; |
| import com.sun.mirror.declaration.AnnotationTypeElementDeclaration; |
| import com.sun.mirror.declaration.AnnotationValue; |
| import com.sun.mirror.type.AnnotationType; |
| import com.sun.mirror.util.SourcePosition; |
| |
| /** |
| * Annotation instance from source. |
| */ |
| public class AnnotationMirrorImpl implements AnnotationMirror, EclipseMirrorObject |
| { |
| /**The ast node that correspond to the annotation.*/ |
| private final IAnnotationBinding _domAnnotation; |
| private final BaseProcessorEnv _env; |
| /** the declaration that is annotated by this annotation or the annotation element declaration |
| * if this is (part of) a default value*/ |
| private final EclipseDeclarationImpl _annotated; |
| |
| public AnnotationMirrorImpl(IAnnotationBinding annotationAstNode, EclipseDeclarationImpl decl, BaseProcessorEnv env) |
| { |
| _domAnnotation = annotationAstNode; |
| _env = env; |
| _annotated = decl; |
| assert _domAnnotation != null : "annotation node missing."; //$NON-NLS-1$ |
| assert _annotated != null : "missing the declaration that is annotated with this annotation."; //$NON-NLS-1$ |
| } |
| |
| public AnnotationType getAnnotationType() |
| { |
| final ITypeBinding binding = _domAnnotation.getAnnotationType(); |
| if( binding == null || binding.isRecovered() ){ |
| final ASTNode node = _annotated.getCompilationUnit().findDeclaringNode(_domAnnotation); |
| String name = ""; //$NON-NLS-1$ |
| if( node != null && node instanceof Annotation ){ |
| final Name typeNameNode = ((Annotation)node).getTypeName(); |
| if( typeNameNode != null ) |
| name = typeNameNode.toString(); |
| } |
| return Factory.createErrorAnnotationType(name); |
| } |
| else |
| return (AnnotationType)Factory.createReferenceType(binding, _env); |
| } |
| |
| public Map<AnnotationTypeElementDeclaration, AnnotationValue> getElementValues() |
| { |
| final IMemberValuePairBinding[] pairs = _domAnnotation.getDeclaredMemberValuePairs(); |
| if (pairs.length == 0) { |
| return Collections.emptyMap(); |
| } |
| |
| final Map<AnnotationTypeElementDeclaration, AnnotationValue> result = |
| new LinkedHashMap<AnnotationTypeElementDeclaration, AnnotationValue>(pairs.length * 4 / 3 + 1 ); |
| for( IMemberValuePairBinding pair : pairs ){ |
| final String name = pair.getName(); |
| if( name == null ) continue; |
| IMethodBinding elementMethod = pair.getMethodBinding(); |
| if( elementMethod != null ){ |
| final EclipseDeclarationImpl mirrorDecl = Factory.createDeclaration(elementMethod, _env); |
| if( mirrorDecl != null && mirrorDecl.kind() == EclipseMirrorObject.MirrorKind.ANNOTATION_ELEMENT ) |
| { |
| final AnnotationTypeElementDeclaration elementDecl = |
| (AnnotationTypeElementDeclaration)mirrorDecl; |
| final AnnotationValue annoValue = |
| Factory.createAnnotationMemberValue(pair.getValue(), name, this, _env, elementDecl.getReturnType()); |
| if( annoValue != null ) |
| result.put( elementDecl, annoValue); |
| } |
| } |
| } |
| return result; |
| } |
| |
| public SourcePosition getPosition() |
| { |
| if( isFromSource() ){ |
| final CompilationUnit unit = _annotated.getCompilationUnit(); |
| final org.eclipse.jdt.core.dom.Annotation annotation = getAstNode(); |
| if( annotation == null ) return null; |
| org.eclipse.jdt.core.dom.ASTNode astNode = annotation.getTypeName(); |
| if( astNode == null ) |
| astNode = annotation; |
| |
| final int offset = astNode.getStartPosition(); |
| return new SourcePositionImpl(astNode.getStartPosition(), |
| astNode.getLength(), |
| unit.getLineNumber(offset), |
| unit.getColumnNumber(offset), |
| _annotated); |
| } |
| return null; |
| } |
| |
| public String toString() |
| { |
| return _domAnnotation.toString(); |
| } |
| |
| /** |
| * @return the type(s) of the member value named <code>membername</code>. |
| * If the value is a class literal, then return the type binding corresponding to the type requested. |
| * Otherwise, return the type of the expression. |
| * If the value is an array initialization, then the type of each of the initialization expresion will |
| * be returned. Return null if no match is found. |
| */ |
| public ITypeBinding[] getMemberValueTypeBinding(String membername) |
| { |
| if( membername == null ) return null; |
| final IMemberValuePairBinding[] declaredPairs = _domAnnotation.getDeclaredMemberValuePairs(); |
| for( IMemberValuePairBinding pair : declaredPairs ){ |
| if( membername.equals(pair.getName()) ){ |
| final Object value = pair.getValue(); |
| return getValueTypeBinding(value, pair.getMethodBinding().getReturnType()); |
| } |
| } |
| |
| // didn't find it in the ast, check the default values. |
| final IMethodBinding binding = getMethodBinding(membername); |
| if(binding == null ) return null; |
| final Object defaultValue = binding.getDefaultValue(); |
| if( defaultValue != null ) |
| return getValueTypeBinding(defaultValue, binding.getReturnType() ); |
| else |
| return null; |
| } |
| |
| private ITypeBinding[] getValueTypeBinding(Object value, final ITypeBinding resolvedType) |
| { |
| if( value == null ) return null; |
| if( resolvedType.isPrimitive() || resolvedType.isAnnotation() || value instanceof String ) |
| return new ITypeBinding[]{ resolvedType }; |
| else if( resolvedType.isArray() ){ |
| final Object[] elements = (Object[])value; |
| final ITypeBinding[] result = new ITypeBinding[elements.length]; |
| final ITypeBinding leafType = resolvedType.getElementType(); |
| for(int i=0, len = elements.length; i<len; i++ ){ |
| final ITypeBinding[] t = getValueTypeBinding(elements[i], leafType); |
| result[i] = t == null ? null : t[0]; |
| } |
| return result; |
| } |
| else if( value instanceof IVariableBinding ) |
| return new ITypeBinding[]{ ( (IVariableBinding)value ).getDeclaringClass() }; |
| else if( value instanceof ITypeBinding ) |
| return new ITypeBinding[]{ (ITypeBinding)value }; |
| else |
| throw new IllegalStateException("value = " + value + " resolvedType = " + resolvedType ); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| } |
| |
| /** |
| * @param memberName the name of the member |
| * @return the value of the given member |
| */ |
| public Object getValue(final String memberName) |
| { |
| if( memberName == null ) return null; |
| final IMemberValuePairBinding[] declaredPairs = _domAnnotation.getDeclaredMemberValuePairs(); |
| for( IMemberValuePairBinding pair : declaredPairs ){ |
| if( memberName.equals(pair.getName()) ){ |
| return pair.getValue(); |
| } |
| } |
| |
| // didn't find it in the ast, check the default values. |
| final IMethodBinding binding = getMethodBinding(memberName); |
| if(binding == null ) return null; |
| return binding.getDefaultValue(); |
| } |
| |
| /** |
| * @return the method binding that matches the given name from the annotation type |
| * referenced by this annotation. |
| */ |
| public IMethodBinding getMethodBinding(final String memberName) |
| { |
| if( memberName == null ) return null; |
| final ITypeBinding typeBinding = _domAnnotation.getAnnotationType(); |
| if( typeBinding == null ) return null; |
| final IMethodBinding[] methods = typeBinding.getDeclaredMethods(); |
| for( IMethodBinding method : methods ){ |
| if( memberName.equals(method.getName()) ) |
| return method; |
| } |
| return null; |
| } |
| |
| public IAnnotationBinding getResolvedAnnotaion(){return _domAnnotation; } |
| |
| |
| |
| public MirrorKind kind(){ return MirrorKind.ANNOTATION_MIRROR; } |
| |
| boolean isFromSource() |
| { |
| return _annotated.isFromSource(); |
| } |
| |
| org.eclipse.jdt.core.dom.Annotation getAstNode() |
| { |
| if( isFromSource() ){ |
| final CompilationUnit unit = _annotated.getCompilationUnit(); |
| final ASTNode node = unit.findDeclaringNode(_domAnnotation); |
| if( node instanceof org.eclipse.jdt.core.dom.Annotation ) |
| return (org.eclipse.jdt.core.dom.Annotation)node; |
| } |
| return null; |
| } |
| |
| @SuppressWarnings("unchecked") |
| ASTNode getASTNodeForElement(String name) |
| { |
| if( name == null ) return null; |
| final org.eclipse.jdt.core.dom.Annotation anno = getAstNode(); |
| if( anno != null ){ |
| if( anno.isSingleMemberAnnotation() ){ |
| if( "value".equals(name) ) //$NON-NLS-1$ |
| return ((SingleMemberAnnotation)anno).getValue(); |
| } |
| else if( anno.isNormalAnnotation() ){ |
| final List<MemberValuePair> pairs = ((NormalAnnotation)anno).values(); |
| for( MemberValuePair pair : pairs ) |
| { |
| final String pairName = pair.getName() == null ? null : pair.getName().toString(); |
| if( name.equals(pairName) ) |
| return pair.getValue(); |
| } |
| } |
| } |
| // marker annotation or no match. |
| return null; |
| } |
| |
| CompilationUnit getCompilationUnit() { return _annotated.getCompilationUnit(); } |
| |
| public BaseProcessorEnv getEnvironment(){ return _env; } |
| |
| public IFile getResource() |
| { return _annotated.getResource(); } |
| |
| public EclipseDeclarationImpl getAnnotatedDeclaration(){ return _annotated; } |
| |
| public boolean equals(Object obj){ |
| if( obj instanceof AnnotationMirrorImpl ){ |
| return ((AnnotationMirrorImpl)obj)._domAnnotation == _domAnnotation; |
| } |
| return false; |
| } |
| |
| public int hashCode(){ |
| return _domAnnotation.hashCode(); |
| } |
| } |