package com.car2go.endpoint2mock2; import com.google.auto.service.AutoService; import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.FieldSpec; import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.TypeSpec; import java.io.IOException; import java.util.HashSet; import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.Processor; import javax.annotation.processing.RoundEnvironment; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic; import retrofit2.http.DELETE; import retrofit2.http.GET; import retrofit2.http.POST; import retrofit2.http.PUT; import static java.util.Collections.singleton; import static javax.lang.model.SourceVersion.latestSupported; @AutoService(Processor.class) public class MockAnnotationProccessor extends AbstractProcessor{ private CodeBlock.Builder initializationBlockBuilder; @Override public synchronized void init(ProcessingEnvironment processingEnvironment) { super.init(processingEnvironment); initializationBlockBuilder = CodeBlock.builder(); } @Override public Set<String> getSupportedAnnotationTypes() { return singleton(MockedEndpoint.class.getCanonicalName()); } @Override public SourceVersion getSupportedSourceVersion() { return latestSupported(); } @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(MockedEndpoint.class); for (Element element : elements) { try { String path = extractPath(element); initializationBlockBuilder.add("registry.add($S);\n", path); } catch (NoAnnotationException e) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "No GET, POST, DELETE, or PUT annotation", element); return true; } } if (elements.size() != 0) { FieldSpec registryField = FieldSpec.builder(Set.class, "registry", Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL) .initializer("new $T();", HashSet.class) .build(); MethodSpec getMockedEndpoints = MethodSpec.methodBuilder("getMockedEndpoints") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(Set.class) .addCode("return registry;\n") .build(); TypeSpec FakeRegistry = TypeSpec.classBuilder("FakeRegistry") .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addField(registryField) .addStaticBlock(initializationBlockBuilder.build()) .addMethod(getMockedEndpoints) .build(); try { JavaFile.builder("com.car2go.mock", FakeRegistry) .build() .writeTo(processingEnv.getFiler()); } catch (IOException e) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "IOException: " + e); return true; } } return true; } private static String extractPath(Element element) throws NoAnnotationException { GET getAnnotation = element.getAnnotation(GET.class); if (getAnnotation != null) { return getAnnotation.value(); } POST postAnnotation = element.getAnnotation(POST.class); if (postAnnotation != null) { return postAnnotation.value(); } DELETE deleteAnnotation = element.getAnnotation(DELETE.class); if (deleteAnnotation != null) { return deleteAnnotation.value(); } PUT putAnnotation = element.getAnnotation(PUT.class); if (putAnnotation != null) { return putAnnotation.value(); } throw new NoAnnotationException(); } /** * Thrown when there is no {@link GET}, {@link POST}, {@link PUT} or {@link DELETE} annotation for the method. */ private static class NoAnnotationException extends Exception { } }