/******************************************************************************* * 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; } } }