diff --git a/build.gradle b/build.gradle index 6e919f67..06bef29a 100644 --- a/build.gradle +++ b/build.gradle @@ -23,18 +23,23 @@ ext { targetVersionCode = 45 targetVersionName = "1.5.5" + def autoServiceVersion = '1.0-rc5' + def gradleIncapHelperVersion = '0.2' deps = [ - android : 'com.google.android:android:1.6_r2', - javapoet : 'com.squareup:javapoet:1.10.0', - junit : 'junit:junit:4.12', - mockito : 'org.mockito:mockito-core:1.10.19', - truth : 'com.google.truth:truth:0.34', - robolectric : 'org.robolectric:robolectric:3.0', - compiletesting: 'com.google.testing.compile:compile-testing:0.15', - asm : ['org.ow2.asm:asm:6.0', 'org.ow2.asm:asm-util:6.0'], - autoservice : 'com.google.auto.service:auto-service:1.0-rc4', - autocommon : 'com.google.auto:auto-common:0.10', - guava : 'com.google.guava:guava:21.0', + android : 'com.google.android:android:1.6_r2', + javapoet : 'com.squareup:javapoet:1.10.0', + junit : 'junit:junit:4.12', + mockito : 'org.mockito:mockito-core:1.10.19', + truth : 'com.google.truth:truth:0.34', + robolectric : 'org.robolectric:robolectric:3.0', + compiletesting : 'com.google.testing.compile:compile-testing:0.15', + asm : ['org.ow2.asm:asm:6.0', 'org.ow2.asm:asm-util:6.0'], + autoserviceAnnotations : "com.google.auto.service:auto-service-annotations:$autoServiceVersion", + autoserviceProcessor : "com.google.auto.service:auto-service:$autoServiceVersion", + autocommon : 'com.google.auto:auto-common:0.10', + guava : 'com.google.guava:guava:21.0', + gradleIncapHelperAnnotations: "net.ltgt.gradle.incap:incap:$gradleIncapHelperVersion", + gradleIncapHelperProcessor : "net.ltgt.gradle.incap:incap-processor:$gradleIncapHelperVersion", ] } diff --git a/moxy-compiler/build.gradle b/moxy-compiler/build.gradle index 7a34e47f..a1ef627f 100644 --- a/moxy-compiler/build.gradle +++ b/moxy-compiler/build.gradle @@ -251,12 +251,15 @@ dependencies { implementation deps.javapoet compileOnly deps.autocommon - compileOnly deps.autoservice + compileOnly deps.autoserviceAnnotations + annotationProcessor deps.autoserviceProcessor compileOnly deps.guava + compileOnly deps.gradleIncapHelperAnnotations + annotationProcessor deps.gradleIncapHelperProcessor javadocDeps project(':moxy') javadocDeps deps.javapoet - javadocDeps deps.autoservice + javadocDeps deps.autoserviceAnnotations testImplementation deps.junit testImplementation deps.truth diff --git a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/MoxyBaseCompiler.java b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/MoxyBaseCompiler.java new file mode 100644 index 00000000..c7ceb69d --- /dev/null +++ b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/MoxyBaseCompiler.java @@ -0,0 +1,42 @@ +package com.arellomobile.mvp.compiler; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic; +import java.util.Set; + +import static javax.lang.model.SourceVersion.latestSupported; + +public abstract class MoxyBaseCompiler extends AbstractProcessor { + + @Override + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + ProcessingEnvironmentHolder.initialize(processingEnv); + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return latestSupported(); + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (annotations.isEmpty()) { + return false; + } + try { + throwableProcess(roundEnv); + } catch (RuntimeException e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.OTHER, "Moxy compilation failed. Could you copy stack trace above and write us (or make issue on Github)?"); + e.printStackTrace(); + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Moxy compilation failed; see the compiler error output for details (" + e + ")"); + } + return false; + } + + protected abstract void throwableProcess(RoundEnvironment roundEnv); +} diff --git a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/MoxyReflectorCompiler.java b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/MoxyReflectorCompiler.java new file mode 100644 index 00000000..a6cca32c --- /dev/null +++ b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/MoxyReflectorCompiler.java @@ -0,0 +1,123 @@ +package com.arellomobile.mvp.compiler; + +import com.arellomobile.mvp.GenerateViewState; +import com.arellomobile.mvp.InjectViewState; +import com.arellomobile.mvp.RegisterMoxyReflectorPackages; +import com.arellomobile.mvp.compiler.presenterbinder.InjectPresenterProcessor; +import com.arellomobile.mvp.compiler.reflector.MoxyReflectorGenerator; +import com.arellomobile.mvp.compiler.viewstate.ViewInterfaceProcessor; +import com.arellomobile.mvp.compiler.viewstateprovider.InjectViewStateProcessor; +import com.arellomobile.mvp.presenter.InjectPresenter; +import com.google.auto.service.AutoService; +import net.ltgt.gradle.incap.IncrementalAnnotationProcessor; +import net.ltgt.gradle.incap.IncrementalAnnotationProcessorType; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.tools.Diagnostic; +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@AutoService(Processor.class) +@IncrementalAnnotationProcessor(IncrementalAnnotationProcessorType.AGGREGATING) +public class MoxyReflectorCompiler extends MoxyBaseCompiler { + + public static final String MOXY_REFLECTOR_DEFAULT_PACKAGE = "com.arellomobile.mvp"; + private static final String OPTION_MOXY_REFLECTOR_PACKAGE = "moxyReflectorPackage"; + + private final Map processorOptions = new HashMap<>(); + + @Override + public synchronized void init(final ProcessingEnvironment processingEnv) { + super.init(processingEnv); + processorOptions.putAll(processingEnv.getOptions()); + } + + @Override + public Set getSupportedOptions() { + return Collections.singleton(OPTION_MOXY_REFLECTOR_PACKAGE); + } + + @Override + public Set getSupportedAnnotationTypes() { + final Set supportedAnnotationTypes = new HashSet<>(); + Collections.addAll(supportedAnnotationTypes, + InjectPresenter.class.getCanonicalName(), + InjectViewState.class.getCanonicalName(), + GenerateViewState.class.getCanonicalName(), + RegisterMoxyReflectorPackages.class.getCanonicalName()); + return supportedAnnotationTypes; + } + + @Override + protected void throwableProcess(RoundEnvironment roundEnv) { + String moxyReflectorPackage = processorOptions.get(OPTION_MOXY_REFLECTOR_PACKAGE); + if (moxyReflectorPackage == null) { + moxyReflectorPackage = MOXY_REFLECTOR_DEFAULT_PACKAGE; + } + + final InjectViewStateProcessor injectViewStateProcessor = new InjectViewStateProcessor(); + final InjectPresenterProcessor injectPresenterProcessor = new InjectPresenterProcessor(); + final ViewInterfaceProcessor viewInterfaceProcessor = new ViewInterfaceProcessor(); + processInjectors(roundEnv, InjectViewState.class, ElementKind.CLASS, injectViewStateProcessor); + processInjectors(roundEnv, InjectPresenter.class, ElementKind.FIELD, injectPresenterProcessor); + final List additionalMoxyReflectorPackages = getAdditionalMoxyReflectorPackages(roundEnv); + try { + MoxyReflectorGenerator.generate( + moxyReflectorPackage, + injectViewStateProcessor.getPresenterClassNames(), + injectPresenterProcessor.getPresentersContainers(), + viewInterfaceProcessor.getUsedStrategies(), + additionalMoxyReflectorPackages + ).writeTo(processingEnv.getFiler()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void processInjectors(RoundEnvironment roundEnv, + Class clazz, + ElementKind kind, + ElementProcessor processor) { + + for (Element element : roundEnv.getElementsAnnotatedWith(clazz)) { + if (element.getKind() != kind) { + ProcessingEnvironmentHolder.getMessager().printMessage(Diagnostic.Kind.ERROR, + element + " must be " + kind.name() + ", or not mark it as @" + clazz.getSimpleName()); + } + + if (element.getKind() != kind) { + ProcessingEnvironmentHolder.getMessager().printMessage(Diagnostic.Kind.ERROR, element + " must be " + kind.name()); + } + + //noinspection unchecked + processor.process((E) element); + } + } + + private List getAdditionalMoxyReflectorPackages(RoundEnvironment roundEnv) { + List result = new ArrayList<>(); + + for (Element element : roundEnv.getElementsAnnotatedWith(RegisterMoxyReflectorPackages.class)) { + if (element.getKind() != ElementKind.CLASS) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, element + " must be " + ElementKind.CLASS.name() + ", or not mark it as @" + RegisterMoxyReflectorPackages.class.getSimpleName()); + } + + String[] packages = element.getAnnotation(RegisterMoxyReflectorPackages.class).value(); + + Collections.addAll(result, packages); + } + + return result; + } +} diff --git a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/MvpCompiler.java b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/MvpCompiler.java index 4c6f88d1..9a1402cc 100644 --- a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/MvpCompiler.java +++ b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/MvpCompiler.java @@ -2,10 +2,8 @@ import com.arellomobile.mvp.GenerateViewState; import com.arellomobile.mvp.InjectViewState; -import com.arellomobile.mvp.RegisterMoxyReflectorPackages; import com.arellomobile.mvp.compiler.presenterbinder.InjectPresenterProcessor; import com.arellomobile.mvp.compiler.presenterbinder.PresenterBinderClassGenerator; -import com.arellomobile.mvp.compiler.reflector.MoxyReflectorGenerator; import com.arellomobile.mvp.compiler.viewstate.ViewInterfaceProcessor; import com.arellomobile.mvp.compiler.viewstate.ViewStateClassGenerator; import com.arellomobile.mvp.compiler.viewstateprovider.InjectViewStateProcessor; @@ -13,31 +11,21 @@ import com.arellomobile.mvp.presenter.InjectPresenter; import com.google.auto.service.AutoService; import com.squareup.javapoet.JavaFile; +import net.ltgt.gradle.incap.IncrementalAnnotationProcessor; +import net.ltgt.gradle.incap.IncrementalAnnotationProcessorType; -import java.io.IOException; -import java.lang.annotation.Annotation; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.annotation.processing.AbstractProcessor; -import javax.annotation.processing.Messager; -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.ElementKind; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; -import javax.lang.model.util.Elements; -import javax.lang.model.util.Types; import javax.tools.Diagnostic; - -import static javax.lang.model.SourceVersion.latestSupported; +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; /** * Date: 12.12.2015 @@ -48,42 +36,8 @@ @SuppressWarnings("unused") @AutoService(Processor.class) -public class MvpCompiler extends AbstractProcessor { - public static final String MOXY_REFLECTOR_DEFAULT_PACKAGE = "com.arellomobile.mvp"; - - private static final String OPTION_MOXY_REFLECTOR_PACKAGE = "moxyReflectorPackage"; - - private static Messager sMessager; - private static Types sTypeUtils; - private static Elements sElementUtils; - private static Map sOptions; - - public static Messager getMessager() { - return sMessager; - } - - public static Types getTypeUtils() { - return sTypeUtils; - } - - public static Elements getElementUtils() { - return sElementUtils; - } - - @Override - public synchronized void init(ProcessingEnvironment processingEnv) { - super.init(processingEnv); - - sMessager = processingEnv.getMessager(); - sTypeUtils = processingEnv.getTypeUtils(); - sElementUtils = processingEnv.getElementUtils(); - sOptions = processingEnv.getOptions(); - } - - @Override - public Set getSupportedOptions() { - return Collections.singleton(OPTION_MOXY_REFLECTOR_PACKAGE); - } +@IncrementalAnnotationProcessor(IncrementalAnnotationProcessorType.ISOLATING) +public class MvpCompiler extends MoxyBaseCompiler { @Override public Set getSupportedAnnotationTypes() { @@ -91,34 +45,12 @@ public Set getSupportedAnnotationTypes() { Collections.addAll(supportedAnnotationTypes, InjectPresenter.class.getCanonicalName(), InjectViewState.class.getCanonicalName(), - RegisterMoxyReflectorPackages.class.getCanonicalName(), GenerateViewState.class.getCanonicalName()); return supportedAnnotationTypes; } @Override - public SourceVersion getSupportedSourceVersion() { - return latestSupported(); - } - - @Override - public boolean process(Set annotations, RoundEnvironment roundEnv) { - if (annotations.isEmpty()) { - return false; - } - - try { - return throwableProcess(roundEnv); - } catch (RuntimeException e) { - getMessager().printMessage(Diagnostic.Kind.OTHER, "Moxy compilation failed. Could you copy stack trace above and write us (or make issue on Github)?"); - e.printStackTrace(); - getMessager().printMessage(Diagnostic.Kind.ERROR, "Moxy compilation failed; see the compiler error output for details (" + e + ")"); - } - - return true; - } - - private boolean throwableProcess(RoundEnvironment roundEnv) { + protected void throwableProcess(RoundEnvironment roundEnv) { checkInjectors(roundEnv, InjectPresenter.class, new PresenterInjectorRules(ElementKind.FIELD, Modifier.PUBLIC, Modifier.DEFAULT)); InjectViewStateProcessor injectViewStateProcessor = new InjectViewStateProcessor(); @@ -136,48 +68,10 @@ private boolean throwableProcess(RoundEnvironment roundEnv) { injectPresenterProcessor, presenterBinderClassGenerator); for (TypeElement usedView : injectViewStateProcessor.getUsedViews()) { - generateCode(usedView, ElementKind.INTERFACE, - viewInterfaceProcessor, viewStateClassGenerator); - } - - String moxyReflectorPackage = sOptions.get(OPTION_MOXY_REFLECTOR_PACKAGE); - - if (moxyReflectorPackage == null) { - moxyReflectorPackage = MOXY_REFLECTOR_DEFAULT_PACKAGE; + generateCode(usedView, ElementKind.INTERFACE, viewInterfaceProcessor, viewStateClassGenerator); } - - List additionalMoxyReflectorPackages = getAdditionalMoxyReflectorPackages(roundEnv); - - JavaFile moxyReflector = MoxyReflectorGenerator.generate( - moxyReflectorPackage, - injectViewStateProcessor.getPresenterClassNames(), - injectPresenterProcessor.getPresentersContainers(), - viewInterfaceProcessor.getUsedStrategies(), - additionalMoxyReflectorPackages - ); - - createSourceFile(moxyReflector); - - return true; } - private List getAdditionalMoxyReflectorPackages(RoundEnvironment roundEnv) { - List result = new ArrayList<>(); - - for (Element element : roundEnv.getElementsAnnotatedWith(RegisterMoxyReflectorPackages.class)) { - if (element.getKind() != ElementKind.CLASS) { - getMessager().printMessage(Diagnostic.Kind.ERROR, element + " must be " + ElementKind.CLASS.name() + ", or not mark it as @" + RegisterMoxyReflectorPackages.class.getSimpleName()); - } - - String[] packages = element.getAnnotation(RegisterMoxyReflectorPackages.class).value(); - - Collections.addAll(result, packages); - } - - return result; - } - - private void checkInjectors(final RoundEnvironment roundEnv, Class clazz, AnnotationRule annotationRule) { for (Element annotatedElement : roundEnv.getElementsAnnotatedWith(clazz)) { annotationRule.checkAnnotation(annotatedElement); @@ -185,7 +79,7 @@ private void checkInjectors(final RoundEnvironment roundEnv, Class 0) { - getMessager().printMessage(Diagnostic.Kind.ERROR, errorStack); + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, errorStack); } } @@ -196,7 +90,7 @@ private void processInjectors(RoundEnvironment roundEnv, JavaFilesGenerator classGenerator) { for (Element element : roundEnv.getElementsAnnotatedWith(clazz)) { if (element.getKind() != kind) { - getMessager().printMessage(Diagnostic.Kind.ERROR, + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, element + " must be " + kind.name() + ", or not mark it as @" + clazz.getSimpleName()); } @@ -209,7 +103,7 @@ private void generateCode(Element element, ElementProcessor processor, JavaFilesGenerator classGenerator) { if (element.getKind() != kind) { - getMessager().printMessage(Diagnostic.Kind.ERROR, element + " must be " + kind.name()); + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, element + " must be " + kind.name()); } //noinspection unchecked diff --git a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/PresenterInjectorRules.java b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/PresenterInjectorRules.java index 350bfcf2..ba4bb379 100644 --- a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/PresenterInjectorRules.java +++ b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/PresenterInjectorRules.java @@ -83,7 +83,7 @@ private void checkEnvironment(final Element annotatedField) { } } if (!result) { - MvpCompiler.getMessager().printMessage(Diagnostic.Kind.ERROR, "You can not use @InjectPresenter in classes that are not View, which is typified target Presenter", annotatedField); + ProcessingEnvironmentHolder.getMessager().printMessage(Diagnostic.Kind.ERROR, "You can not use @InjectPresenter in classes that are not View, which is typified target Presenter", annotatedField); } } diff --git a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/ProcessingEnvironmentHolder.java b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/ProcessingEnvironmentHolder.java new file mode 100644 index 00000000..8c553910 --- /dev/null +++ b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/ProcessingEnvironmentHolder.java @@ -0,0 +1,41 @@ +package com.arellomobile.mvp.compiler; + +import javax.annotation.processing.Messager; +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; + +public class ProcessingEnvironmentHolder { + + private static final Object sAccessLock = new Object(); + + private static Messager sMessager; + private static Types sTypeUtils; + private static Elements sElementUtils; + + public static void initialize(ProcessingEnvironment environment) { + synchronized (sAccessLock) { + sMessager = environment.getMessager(); + sTypeUtils = environment.getTypeUtils(); + sElementUtils = environment.getElementUtils(); + } + } + + public static Messager getMessager() { + synchronized (sAccessLock) { + return sMessager; + } + } + + public static Types getTypeUtils() { + synchronized (sAccessLock) { + return sTypeUtils; + } + } + + public static Elements getElementUtils() { + synchronized (sAccessLock) { + return sElementUtils; + } + } +} diff --git a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/Util.java b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/Util.java index 98b3ec95..8faed037 100644 --- a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/Util.java +++ b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/Util.java @@ -110,7 +110,7 @@ public static String getFullClassName(TypeMirror typeMirror) { } public static String getFullClassName(TypeElement typeElement) { - String packageName = MvpCompiler.getElementUtils().getPackageOf(typeElement).getQualifiedName().toString(); + String packageName = ProcessingEnvironmentHolder.getElementUtils().getPackageOf(typeElement).getQualifiedName().toString(); if (packageName.length() > 0) { packageName += "."; } diff --git a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/presenterbinder/PresenterBinderClassGenerator.java b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/presenterbinder/PresenterBinderClassGenerator.java index 1165499e..170c3ff4 100644 --- a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/presenterbinder/PresenterBinderClassGenerator.java +++ b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/presenterbinder/PresenterBinderClassGenerator.java @@ -59,7 +59,8 @@ public List generate(TargetClassInfo targetClassInfo) { TypeSpec.Builder classBuilder = TypeSpec.classBuilder(containerSimpleName + MvpProcessor.PRESENTER_BINDER_SUFFIX) .addModifiers(Modifier.PUBLIC) - .superclass(ParameterizedTypeName.get(ClassName.get(PresenterBinder.class), targetClassName)); + .superclass(ParameterizedTypeName.get(ClassName.get(PresenterBinder.class), targetClassName)) + .addOriginatingElement(targetClassInfo.getElement()); for (TargetPresenterField field : fields) { classBuilder.addType(generatePresenterBinderClass(field, targetClassName)); diff --git a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/presenterbinder/TargetClassInfo.java b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/presenterbinder/TargetClassInfo.java index 0c739bd2..2004004a 100644 --- a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/presenterbinder/TargetClassInfo.java +++ b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/presenterbinder/TargetClassInfo.java @@ -7,19 +7,23 @@ import javax.lang.model.element.TypeElement; class TargetClassInfo { - private final ClassName name; + private final TypeElement name; private final List fields; TargetClassInfo(TypeElement name, List fields) { - this.name = ClassName.get(name); + this.name = name; this.fields = fields; } ClassName getName() { - return name; + return ClassName.get(name); } List getFields() { return fields; } + + TypeElement getElement() { + return name; + } } diff --git a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/reflector/MoxyReflectorGenerator.java b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/reflector/MoxyReflectorGenerator.java index 2bf16a20..d8ce7a68 100644 --- a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/reflector/MoxyReflectorGenerator.java +++ b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/reflector/MoxyReflectorGenerator.java @@ -11,6 +11,11 @@ import com.squareup.javapoet.TypeSpec; import com.squareup.javapoet.WildcardTypeName; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; @@ -20,13 +25,7 @@ import java.util.SortedMap; import java.util.TreeMap; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.TypeElement; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; - -import static com.arellomobile.mvp.compiler.MvpCompiler.MOXY_REFLECTOR_DEFAULT_PACKAGE; +import static com.arellomobile.mvp.compiler.MoxyReflectorCompiler.MOXY_REFLECTOR_DEFAULT_PACKAGE; /** * Date: 07.12.2016 @@ -58,6 +57,8 @@ public static JavaFile generate(String destinationPackage, .addField(MAP_CLASS_TO_LIST_OF_OBJECT_TYPE_NAME, "sPresenterBinders", Modifier.PRIVATE, Modifier.STATIC) .addField(MAP_CLASS_TO_OBJECT_TYPE_NAME, "sStrategies", Modifier.PRIVATE, Modifier.STATIC); + addOriginatingElements(classBuilder, Arrays.asList(presenterClassNames, presentersContainers, strategyClasses)); + classBuilder.addStaticBlock(generateStaticInitializer(presenterClassNames, presentersContainers, strategyClasses, additionalMoxyReflectorsPackages)); if (destinationPackage.equals(MOXY_REFLECTOR_DEFAULT_PACKAGE)) { @@ -106,12 +107,23 @@ public static JavaFile generate(String destinationPackage, .build()); } - return JavaFile.builder(destinationPackage, classBuilder.build()) .indent("\t") .build(); } + private static void addOriginatingElements(TypeSpec.Builder builder, Iterable> typeElements) { + if (builder != null && typeElements != null) { + for (final Iterable elements : typeElements) { + if (elements != null) { + for (final TypeElement element : elements) { + builder.addOriginatingElement(element); + } + } + } + } + } + private static CodeBlock generateStaticInitializer(List presenterClassNames, List presentersContainers, List strategyClasses, diff --git a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstate/ViewInterfaceProcessor.java b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstate/ViewInterfaceProcessor.java index 18d8a960..e3289dce 100644 --- a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstate/ViewInterfaceProcessor.java +++ b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstate/ViewInterfaceProcessor.java @@ -1,7 +1,7 @@ package com.arellomobile.mvp.compiler.viewstate; import com.arellomobile.mvp.compiler.ElementProcessor; -import com.arellomobile.mvp.compiler.MvpCompiler; +import com.arellomobile.mvp.compiler.ProcessingEnvironmentHolder; import com.arellomobile.mvp.compiler.Util; import com.arellomobile.mvp.viewstate.strategy.AddToEndStrategy; import com.arellomobile.mvp.viewstate.strategy.StateStrategyType; @@ -35,7 +35,7 @@ */ public class ViewInterfaceProcessor extends ElementProcessor { private static final String STATE_STRATEGY_TYPE_ANNOTATION = StateStrategyType.class.getName(); - private static final TypeElement DEFAULT_STATE_STRATEGY = MvpCompiler.getElementUtils().getTypeElement(AddToEndStrategy.class.getCanonicalName()); + private static final TypeElement DEFAULT_STATE_STRATEGY = ProcessingEnvironmentHolder.getElementUtils().getTypeElement(AddToEndStrategy.class.getCanonicalName()); private TypeElement viewInterfaceElement; private String viewInterfaceName; @@ -100,7 +100,7 @@ private void getMethods(TypeElement typeElement, methodElement.getSimpleName(), methodElement.getReturnType() ); - MvpCompiler.getMessager().printMessage(Diagnostic.Kind.ERROR, message); + ProcessingEnvironmentHolder.getMessager().printMessage(Diagnostic.Kind.ERROR, message); } AnnotationMirror annotation = Util.getAnnotation(methodElement, STATE_STRATEGY_TYPE_ANNOTATION); diff --git a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstate/ViewMethod.java b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstate/ViewMethod.java index c4446751..ae5d4604 100644 --- a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstate/ViewMethod.java +++ b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstate/ViewMethod.java @@ -1,6 +1,6 @@ package com.arellomobile.mvp.compiler.viewstate; -import com.arellomobile.mvp.compiler.MvpCompiler; +import com.arellomobile.mvp.compiler.ProcessingEnvironmentHolder; import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeVariableName; @@ -46,7 +46,7 @@ class ViewMethod { this.parameterSpecs = new ArrayList<>(); - Types typeUtils = MvpCompiler.getTypeUtils(); + Types typeUtils = ProcessingEnvironmentHolder.getTypeUtils(); ExecutableType executableType = (ExecutableType) typeUtils.asMemberOf(targetInterfaceElement, methodElement); List parameters = methodElement.getParameters(); List resolvedParameterTypes = executableType.getParameterTypes(); diff --git a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstate/ViewStateClassGenerator.java b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstate/ViewStateClassGenerator.java index c6463429..5b28b376 100644 --- a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstate/ViewStateClassGenerator.java +++ b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstate/ViewStateClassGenerator.java @@ -2,7 +2,7 @@ import com.arellomobile.mvp.MvpProcessor; import com.arellomobile.mvp.compiler.JavaFilesGenerator; -import com.arellomobile.mvp.compiler.MvpCompiler; +import com.arellomobile.mvp.compiler.ProcessingEnvironmentHolder; import com.arellomobile.mvp.viewstate.MvpViewState; import com.arellomobile.mvp.viewstate.ViewCommand; import com.squareup.javapoet.ClassName; @@ -37,6 +37,7 @@ public List generate(ViewInterfaceInfo viewInterfaceInfo) { DeclaredType viewInterfaceType = (DeclaredType) viewInterfaceInfo.getElement().asType(); TypeSpec.Builder classBuilder = TypeSpec.classBuilder(viewName.simpleName() + MvpProcessor.VIEW_STATE_SUFFIX) + .addOriginatingElement(viewInterfaceInfo.getElement()) .addModifiers(Modifier.PUBLIC) .superclass(ParameterizedTypeName.get(ClassName.get(MvpViewState.class), nameWithTypeVariables)) .addSuperinterface(nameWithTypeVariables) @@ -89,7 +90,7 @@ private MethodSpec generateMethod(DeclaredType enclosingType, ViewMethod method, commandFieldName += random.nextInt(10); } - return MethodSpec.overriding(method.getElement(), enclosingType, MvpCompiler.getTypeUtils()) + return MethodSpec.overriding(method.getElement(), enclosingType, ProcessingEnvironmentHolder.getTypeUtils()) .addStatement("$1N $2L = new $1N($3L)", commandClass, commandFieldName, method.getArgumentsString()) .addStatement("mViewCommands.beforeApply($L)", commandFieldName) .addCode("\n") diff --git a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstateprovider/InjectViewStateProcessor.java b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstateprovider/InjectViewStateProcessor.java index 185650f5..f4dc5c23 100644 --- a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstateprovider/InjectViewStateProcessor.java +++ b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstateprovider/InjectViewStateProcessor.java @@ -6,7 +6,7 @@ import com.arellomobile.mvp.MvpPresenter; import com.arellomobile.mvp.MvpProcessor; import com.arellomobile.mvp.compiler.ElementProcessor; -import com.arellomobile.mvp.compiler.MvpCompiler; +import com.arellomobile.mvp.compiler.ProcessingEnvironmentHolder; import com.arellomobile.mvp.compiler.Util; import java.util.ArrayList; @@ -23,7 +23,6 @@ import javax.lang.model.type.MirroredTypeException; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; -import javax.tools.Diagnostic; import static com.arellomobile.mvp.compiler.Util.fillGenerics; @@ -61,7 +60,7 @@ private String getViewStateClassName(TypeElement typeElement) { view = view.substring(0, view.indexOf("<")); } - TypeElement viewTypeElement = MvpCompiler.getElementUtils().getTypeElement(view); + TypeElement viewTypeElement = ProcessingEnvironmentHolder.getElementUtils().getTypeElement(view); if (viewTypeElement == null) { throw new IllegalArgumentException("View \"" + view + "\" for " + typeElement + " cannot be found"); } diff --git a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstateprovider/PresenterInfo.java b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstateprovider/PresenterInfo.java index 19339ba8..0d8346be 100644 --- a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstateprovider/PresenterInfo.java +++ b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstateprovider/PresenterInfo.java @@ -11,19 +11,23 @@ * @author Evgeny Kursakov */ class PresenterInfo { - private final ClassName name; + private final TypeElement name; private final ClassName viewStateName; PresenterInfo(TypeElement name, String viewStateName) { - this.name = ClassName.get(name); + this.name = name; this.viewStateName = ClassName.bestGuess(viewStateName); } ClassName getName() { - return name; + return ClassName.get(name); } ClassName getViewStateName() { return viewStateName; } + + TypeElement getElement() { + return name; + } } diff --git a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstateprovider/ViewStateProviderClassGenerator.java b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstateprovider/ViewStateProviderClassGenerator.java index 28477dc0..a0181cc7 100644 --- a/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstateprovider/ViewStateProviderClassGenerator.java +++ b/moxy-compiler/src/main/java/com/arellomobile/mvp/compiler/viewstateprovider/ViewStateProviderClassGenerator.java @@ -28,6 +28,7 @@ public final class ViewStateProviderClassGenerator extends JavaFilesGenerator generate(PresenterInfo presenterInfo) { TypeSpec typeSpec = TypeSpec.classBuilder(presenterInfo.getName().simpleName() + MvpProcessor.VIEW_STATE_PROVIDER_SUFFIX) + .addOriginatingElement(presenterInfo.getElement()) .addModifiers(Modifier.PUBLIC) .superclass(ViewStateProvider.class) .addMethod(generateGetViewStateMethod(presenterInfo.getName(), presenterInfo.getViewStateName())) diff --git a/moxy-compiler/src/test/java/com/arellomobile/mvp/compiler/CompilerTest.java b/moxy-compiler/src/test/java/com/arellomobile/mvp/compiler/CompilerTest.java index 052fe9fc..72d49e1f 100644 --- a/moxy-compiler/src/test/java/com/arellomobile/mvp/compiler/CompilerTest.java +++ b/moxy-compiler/src/test/java/com/arellomobile/mvp/compiler/CompilerTest.java @@ -13,9 +13,11 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintWriter; +import java.util.Arrays; import java.util.List; import java.util.Optional; +import javax.annotation.processing.Processor; import javax.tools.JavaFileObject; import javax.tools.StandardLocation; @@ -35,17 +37,21 @@ protected Compilation compileSources(JavaFileObject... sources) { protected Compilation compileSourcesWithProcessor(JavaFileObject... sources) { return javac() .withOptions("-implicit:none") // TODO: enable lint (-Xlint:processing) - .withProcessors(new MvpCompiler()) + .withProcessors(getProcessors()) .compile(sources); } protected Compilation compileLibSourcesWithProcessor(String moxyReflectorPackage, JavaFileObject... sources) { return javac() .withOptions("-implicit:none", "-AmoxyReflectorPackage=" + moxyReflectorPackage) - .withProcessors(new MvpCompiler()) + .withProcessors(getProcessors()) .compile(sources); } + private Iterable getProcessors() { + return Arrays.asList(new MvpCompiler(), new MoxyReflectorCompiler()); + } + /** * Asserts that all files from {@code exceptedGeneratedFiles} exists in {@code actualGeneratedFiles} * and have equivalent bytecode