What is the Annotation Processor build problem

For those of you who have written custom annotation processors, this may seem like an easy question at first glance. Yes, there is a whole web site that teaches you how to log, but have you ever wondered how to locate a situation where you can’t even print a log? For example:

/ / confirm the meta-inf/services/javax.mail annotation. Processing. The Processor that's no problem
// Verify that the build script is ok and that the annotation Bridge is used and participated in the build
@AutoService(Processor.class)
public class TestAnnotationProcessor extends AbstractProcessor {
    public TestAnnotationProcessor(a) {
        System.out.println("TestAnnotationProcessor constrator");
    }

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        System.out.println("TestAnnotationProcessor init");
    }

    @Override
    public Set<String> getSupportedAnnotationTypes(a) {
        System.out.println("TestAnnotationProcessor getSupportedAnnotationTypes");
        Set<String> supported = new HashSet<String>();
        supported.add(Bridge.class.getCanonicalName());
        return supported;
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        System.out.println("TestAnnotationProcessor process");
        return true; }}Copy the code

CompileReleaseJavaWithJavac after running the build process not vomit first I the Annotation Processor any line of log, direct error can’t find my Annotation Processor product class reference (that is, direct to compile the class link).

Are you confused? I’m confused anyway! Print log not working, ha ha, environment check ok, what the heck, directly across the Annotation Processor compile.

This is where you’ll need to dig a little deeper into location analysis, assuming you’re familiar with the Annotation Processor fundamentals, and then we’ll go through some additional javac detail logs for example analysis.

The Annotation Processor mechanism

Annotations and annotation handlers are mechanisms introduced in JDK5 to provide additional information for Java structures such as classes, methods, fields, and parameters. The common @Override, for example, is an annotation that only applies to the Java compiler. Java allows us to define custom annotations, and custom annotation handlers are used to handle these custom annotations. Annotation handler trigger times are handled by Javac, so the whole javAC process is briefly described as follows:

As you can see, the JavAC compilation overview diagram is divided into the following steps:

  1. Parse source files into abstract syntax trees.
  2. Invoke the registered annotation handler.
  3. If the annotation processor generates a new source file during processing, the compiler repeats steps 1 and 2 and goes to the final round when the annotation processor does not generate any new source files.
  4. Bytecodes are generated in the actual compile bytecode phase.

Above is the core mechanism of annotation processor, with this understanding of the core mechanism we continue to explore.

The nature of the Annotation Processor under the build tool

The annotation Processor capability provided by JDK is always used more or less in our daily development (both Java backend and Android mobile). Whatever build tool (Gradle, Maven, etc.) essentially specifies which processers are explicitly specified by the javac-processorPath command argument, Or explicitly declared meta-inf/services/javax.mail annotation. Processing. The Processor to be found and invoke javac (see Google’s AutoService framework).

Normally, we use and build Annotation Processor technology in development by following the above steps, and most of the Annotation Processor copied from the network works normally. It’s nice to only deal with the process by ourselves every time, because as long as it is placed according to the rule declaration, The other Javac calls perfectly on its own.

Enhanced JAVAC process printing exposes problems

To solve the problem that the Annotation Processor does not print the scene by adding logs, we need to obtain some additional information to assist positioning. Since the direct use of command line javac is the most primitive operation, Gradle is generally used for construction, and the essence of Gradle is still to call JavAC. Therefore, we take Gradle as an example to analyze how to locate the Annotation Processor problem.

The simplest way to do this is to add parameters to all modules directly in the root directory build.gradle:

/ / 【 craftsman if water to add WeChat yanbo373131686 contact me, concern WeChat public number: code farmers a daily topic Without permission is strictly prohibited reproduced, https://blog.csdn.net/yanbober]

-verbose -xprintrounds -xprintprocessorinfo is optional
allprojects {
    gradle.projectsEvaluated {
        tasks.withType(JavaCompile) {
            options.compilerArgs << "-Xlint" << "-verbose" << "-XprintRounds" << "-XprintProcessorInfo" << "-Xmaxerrs" << "100000"}}}Copy the code

You can also add it only to modules that have their own annotation handlers, as above, by simply adding the arguments to JavaCompile. Javac -help: javac -help: javac -help: javac -help: javac -help: javac -help: javac -help: javac -help

yan@yanDeMackbookPro:~$javac -help usage: javac <options> <source files> Where possible options include: -g generate all debugging information...... -verbose Prints messages about the operation being performed by the compiler...... -processor <class1>[,<class2>,<class3>...] The name of the annotation handler to run; Bypass the default search process - processorPath < path > to specify where to find the comment handler......Copy the code

As for the script on several other javac -help no docs.oracle.com/en/java/jav parameters may have a look of the official document… , which explains the parameter meanings in detail.

Be sure to append your build logs to a disk file after adding the above parameters, as the logs can become very large and easy to locate problems.

Locate problems through build log analysis

Perform your construction tasks, and then analyze and locate the following steps. Each step is a kind of positioning of the scene, step by step.

  1. Search your log for your Processor class name, for exampleTestAnnotationProcessor.class, you will see the following log.
// If your annotation handler is logging in source form in the project [loading] RegularFileObject [/ home/user/yan/test/target/classes/cn/yan/test/TestAnnotationProcessor class]] / / if your annotation processor is dependent jar in the project In the form of a log [loading ZipFileIndexFileObject [... / test. The jar (cn/yan/test/TestAnnotationProcessor. Class)]]Copy the code

Analysis: If the above information is not found in your log, your annotation handler has not been added to javAC’s classpath. General problem is your meta-inf/services/javax.mail annotation. Processing. Processor statement has a problem, javac your annotation Processor cannot be found. Some students may be generated by Google’s AutoService meta-inf/services/javax.mail annotation. Processing. The Processor, In this case, you need to check if this is OK (for example, the classpath of AGP has been modified for some time in the intermediate version of Android, and you need to manually change compile to annotationProcessor).

  1. Search in your journalRoundYou are advised to search for the keywordRound 1:If this format is easier, the log should look like this.
Round 1: input files: {cn.yan.test.Application, ...... , cn.yan.test.UseMarkedAnnotation} annotations: [java.lang.Override, cn.yan.annotation.Bridge] last round: falseCopy the code

Annotations: The annotations handler is configured to handle annotations (such as @cn.yan. Annotate. Bridge).

If Round is not found in the log, javac does not trigger any annotation handlers (either ones you wrote or those that rely on the tripartite framework). The biggest suspect is to check that you have disabled the Javac annotation handler, that is, to make sure javac executes without the -proc: None parameter. If you have Round in your log, but input Files: and Annotations: do not have your annotation class and user class, then you are not using the annotations that your annotation handler is handling in your code.

  1. Search in your journalLoaded cn.yan.test.TestAnnotationProcessorKeyword, the log you see will be as follows.
[Loaded cn.yan.test.TestAnnotationProcessor from file:/home/user/yan/test/target/classes/cn/yan/test/TestAnnotationProcessor.class]
Copy the code

Analysis: If you can’t see the above log, your annotation handler class itself didn’t load successfully. I don’t know how to analyze it, but at least it didn’t load successfully. You may need to check the specification or illegal cause.

  1. If you still can’t find the cause of the problem, you might as well change your mind and carefully check the ordinary Java file you are involved in building, whether there are syntax errors or any problems (such as constants are not declared, etc.); If so, try again when you’re done. Don’t ask me why. I haven’t done much researchjavacThis source code, but I have encountered, and there is no exception stack information, and finally found that the code is missing a variable declaration after merging to resolve the conflict, that is, it simply bypiles the Annotation Processor process and directly compile to class process).
What is the use of this skill?

To tell you the truth, I’m a bit of an old driver. The Annotation Processor has been playing at 6 for a few years now, but recently the project was upgraded and built with Java8 and androidX support. Then the annotation handler and dataBinding in the project all stopped working, and to top it all off, it was really stingy. There was no error stack, and it looked like this:

/ / 【 craftsman if water to add WeChat yanbo373131686 contact me, concern WeChat public number: code farmers a daily topic Without permission is strictly prohibited reproduced https://blog.csdn.net/yanbober 】 FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ': test: compileReleaseJavaWithJavac'. / / there would have been the first spit me annotation processor within the log, and then continue to javac compiler, Compilation failed; see the compiler error output for details. * Exception is: org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':moffice:compileReleaseJavaWithJavac'. at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.lambda$executeIfValid$1(ExecuteActionsTaskExecuter.ja va:200) ...... Caused by: org.gradle.api.internal.tasks.compile.CompilationFailedException: Compilation failed; see the compiler error output for details. at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:57)Copy the code

Gradle build commands have been added to various detailed parameters for view stack and log in detail, but the amazing thing is that he went directly to make a mistake, compileReleaseJavaWithJavac without any error message before and after (there is only one tuo Gradle own task invocation chain). I especially careless, I synchronized the next code, but make up but make up ah, you pour prompt next problem ah! I’m going straight to compile Class without saying anything, skipping the Annotation Processor process, which is pretty annoying. Fortunately, it is fixed according to the above way, haha.