package annotations; import java.util.ArrayList; import java.util.List; import java.util.Map.Entry; import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.RoundEnvironment; import javax.lang.model.element.TypeElement; import javax.annotation.processing.*; import javax.lang.model.SourceVersion; import javax.lang.model.element.*; import javax.lang.model.type.*; import javax.lang.model.util.SimpleTypeVisitor6; import javax.lang.model.util.Types; import javax.tools.Diagnostic; @SupportedAnnotationTypes("annotations.ArgsConstructor") @SupportedSourceVersion(SourceVersion.RELEASE_6) public class ArgsConstructorProcessor extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> annotations,RoundEnvironment env) { for (TypeElement type : annotations) { processArgsConstructorClasses(env, type); } return true; } private void processArgsConstructorClasses(RoundEnvironment env, TypeElement type) { for (Element element : env.getElementsAnnotatedWith(type)) { processClass(element); } } private void processClass(Element element) { String actionName = ArgsConstructor.class.getName(); AnnotationValue action = null; for (AnnotationMirror am : processingEnv.getElementUtils().getAllAnnotationMirrors(element)) { if ( actionName.equals(am.getAnnotationType().toString() ) ) { for (Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : am.getElementValues().entrySet() ) { if ( "value".equals(entry.getKey().getSimpleName().toString() ) ) { action = entry.getValue(); break; } } } } if (action == null) { processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "Class " + element + " lacks an annotation with required args",element); return; } List<TypeMirror> mirrors = new ArrayList<TypeMirror>(); for (Object val: (List<?>)action.getValue()) { AnnotationValue v= (AnnotationValue)val; TypeMirror m =(TypeMirror)v.getValue(); mirrors.add(m); } if (!doesClassContainArgsConstructor(element,mirrors)) { String s = ""; for (TypeMirror tm:mirrors) { if (!s.isEmpty()) { s+=","; } s += tm.toString(); } processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Class " + element + " lacks a public constructor with args: "+s,element); } else { processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Processed type: "+element); } } private boolean doesClassContainArgsConstructor(Element el,List<TypeMirror> annotTypes) { for (Element subelement : el.getEnclosedElements()) { if (subelement.getKind() == ElementKind.CONSTRUCTOR && subelement.getModifiers().contains(Modifier.PUBLIC)) { TypeMirror mirror = subelement.asType(); if (mirror.accept(argsVisitor, annotTypes)) return true; } } return false; } private final TypeVisitor<Boolean, List<TypeMirror>> argsVisitor = new SimpleTypeVisitor6<Boolean, List<TypeMirror>>() { public Boolean visitExecutable(ExecutableType t, List<TypeMirror> annotatedTypes) { List<? extends TypeMirror> types = t.getParameterTypes(); if (annotatedTypes.size() != types.size()) { return false; } Types tutil = processingEnv.getTypeUtils(); for (int i = 0 ; i < types.size(); i++) { TypeMirror test = tutil.erasure(types.get(i));//because same type bad Map<String,String> != Map TypeMirror expected = tutil.erasure(annotatedTypes.get(i)); if (!tutil.isAssignable(expected, test)) { return false; } } return true; } }; }