| /******************************************************************************* |
| * Copyright (c) 2005, 2007 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.tests.annotations.apitest; |
| |
| import java.util.Collection; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.Map.Entry; |
| |
| import org.eclipse.jdt.apt.tests.annotations.BaseFactory; |
| import org.eclipse.jdt.apt.tests.annotations.BaseProcessor; |
| |
| import com.sun.mirror.apt.AnnotationProcessor; |
| import com.sun.mirror.apt.AnnotationProcessorEnvironment; |
| import com.sun.mirror.apt.Messager; |
| import com.sun.mirror.declaration.AnnotationMirror; |
| import com.sun.mirror.declaration.AnnotationTypeDeclaration; |
| import com.sun.mirror.declaration.AnnotationTypeElementDeclaration; |
| import com.sun.mirror.declaration.AnnotationValue; |
| import com.sun.mirror.declaration.Declaration; |
| import com.sun.mirror.declaration.FieldDeclaration; |
| import com.sun.mirror.declaration.MethodDeclaration; |
| import com.sun.mirror.declaration.TypeDeclaration; |
| import com.sun.mirror.declaration.TypeParameterDeclaration; |
| import com.sun.mirror.type.DeclaredType; |
| import com.sun.mirror.type.TypeMirror; |
| import com.sun.mirror.util.Types; |
| |
| |
| public class APIAnnotationProcessorFactory extends BaseFactory { |
| |
| public APIAnnotationProcessorFactory(){ |
| super(Common.class.getName(), SubtypeOf.class.getName(), AssignableTo.class.getName()); |
| } |
| |
| public AnnotationProcessor getProcessorFor( |
| Set<AnnotationTypeDeclaration> decls, |
| AnnotationProcessorEnvironment env) { |
| return new APIAnnotationProcessor(env); |
| } |
| |
| public static class APIAnnotationProcessor extends BaseProcessor{ |
| |
| private Messager _msgr; |
| private Types _types; |
| |
| public APIAnnotationProcessor(AnnotationProcessorEnvironment env){ |
| super(env); |
| } |
| |
| public void process() { |
| _msgr = _env.getMessager(); |
| _types = _env.getTypeUtils(); |
| checkCommon(); |
| checkSubtypeOf(); |
| checkAssignableTo(); |
| } |
| |
| /** |
| * validate instances of the Common annotation |
| */ |
| private void checkCommon() |
| { |
| final AnnotationTypeDeclaration commonAnnoType = |
| (AnnotationTypeDeclaration)_env.getTypeDeclaration(Common.class.getName()); |
| final Collection<Declaration> decls = |
| _env.getDeclarationsAnnotatedWith(commonAnnoType); |
| for( Declaration decl : decls ){ |
| if(decl instanceof FieldDeclaration ){ |
| final FieldDeclaration field = (FieldDeclaration)decl; |
| final TypeMirror type = field.getType(); |
| if( type instanceof DeclaredType ){ |
| final TypeMirror collectionType = |
| _env.getTypeUtils().getDeclaredType(_env.getTypeDeclaration(Collection.class.getName())); |
| final Collection<TypeMirror> typeVars = |
| ((DeclaredType)type).getActualTypeArguments(); |
| if(typeVars.size() == 1 ){ |
| TypeMirror typeVar = typeVars.iterator().next(); |
| boolean assignable = _env.getTypeUtils().isAssignable(typeVar, collectionType); |
| if( assignable ) |
| _msgr.printError(typeVar + " is assignable to " + collectionType ); |
| else |
| _msgr.printError(typeVar + " is not assignable to " + collectionType ); |
| } |
| } |
| }else if(decl instanceof TypeDeclaration){ |
| final TypeDeclaration typeDecl = (TypeDeclaration)decl; |
| final Collection<TypeParameterDeclaration> typeParams = |
| typeDecl.getFormalTypeParameters(); |
| for(TypeParameterDeclaration typeParam : typeParams){ |
| Declaration owner = typeParam.getOwner(); |
| _msgr.printError("Type parameter '" + typeParam + "' belongs to " + owner.getClass().getName() + " " + owner.getSimpleName() ); |
| } |
| } |
| else if( decl instanceof MethodDeclaration ){ |
| final MethodDeclaration methodDecl = (MethodDeclaration)decl; |
| final Collection<TypeParameterDeclaration> typeParams = |
| methodDecl.getFormalTypeParameters(); |
| for(TypeParameterDeclaration typeParam : typeParams){ |
| Declaration owner = typeParam.getOwner(); |
| _msgr.printError("Type parameter '" + typeParam + "' belongs to " + owner.getClass().getName() + " " + owner.getSimpleName() ); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Validate all the fields annotated with @SubtypeOf, in order to test |
| * the Types.subtypeOf() method. |
| * We ignore anything but fields, out of laziness. |
| */ |
| private void checkSubtypeOf() { |
| final AnnotationTypeDeclaration annoType = |
| (AnnotationTypeDeclaration)_env.getTypeDeclaration(SubtypeOf.class.getName()); |
| final Collection<Declaration> decls = |
| _env.getDeclarationsAnnotatedWith(annoType); |
| for( Declaration decl : decls ){ |
| if(decl instanceof FieldDeclaration ) { |
| AnnotationMirror mirror = findMirror(decl, annoType); |
| if (mirror == null) { |
| return; |
| } |
| TypeMirror valueType = getTypeValue(mirror); |
| final FieldDeclaration field = (FieldDeclaration)decl; |
| final TypeMirror fieldType = field.getType(); |
| boolean isSubtype = _types.isSubtype(fieldType, valueType); |
| if( isSubtype ) |
| _msgr.printError(fieldType + " is a subtype of " + valueType ); |
| else |
| _msgr.printError(fieldType + " is not a subtype of " + valueType ); |
| } |
| } |
| } |
| |
| /** |
| * Validate all the fields annotated with @AssignableTo. |
| * We ignore anything but fields, out of laziness. |
| */ |
| private void checkAssignableTo() { |
| final AnnotationTypeDeclaration annoType = |
| (AnnotationTypeDeclaration)_env.getTypeDeclaration(AssignableTo.class.getName()); |
| final Collection<Declaration> decls = |
| _env.getDeclarationsAnnotatedWith(annoType); |
| for( Declaration decl : decls ){ |
| if(decl instanceof FieldDeclaration ) { |
| AnnotationMirror mirror = findMirror(decl, annoType); |
| if (mirror == null) { |
| return; |
| } |
| TypeMirror valueType = getTypeValue(mirror); |
| final FieldDeclaration field = (FieldDeclaration)decl; |
| final TypeMirror fieldType = field.getType(); |
| boolean isAssignableTo = _types.isAssignable(fieldType, valueType); |
| if( isAssignableTo ) |
| _msgr.printError(fieldType + " is assignable to " + valueType ); |
| else |
| _msgr.printError(fieldType + " is not assignable to " + valueType ); |
| } |
| } |
| } |
| |
| /** |
| * @return a mirror for the instance of the specified annotation on the specified |
| * declaration, or null if one is not present. |
| */ |
| private AnnotationMirror findMirror(Declaration decl, AnnotationTypeDeclaration at) { |
| for (AnnotationMirror mirror : decl.getAnnotationMirrors()) { |
| if (mirror.getAnnotationType().equals(at)) { |
| return mirror; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * @return the value() of an annotation instance <code>mirror</code>, if it is a |
| * class value, or null if not. |
| */ |
| private TypeMirror getTypeValue(AnnotationMirror mirror) { |
| Map<AnnotationTypeElementDeclaration, AnnotationValue> values = mirror.getElementValues(); |
| for (Entry<AnnotationTypeElementDeclaration, AnnotationValue> entry : values.entrySet()) { |
| if ("value".equals(entry.getKey().getSimpleName())) { |
| if (entry.getValue().getValue() instanceof TypeMirror) |
| return (TypeMirror)entry.getValue().getValue(); |
| else |
| return null; |
| } |
| } |
| return null; |
| } |
| } |
| } |