1. Introduction

When you think of code staking, you probably think of AspectJ, Transfrom Api + ASM, and so on.

Needless to say, code staking can be used for burying, hot repair, componentized routing, and so on.

However, AspectJ felt awkward and ASM was complex, requiring a custom Gradle plug-in. Fortunately, SOME time ago, I came across a new method called AnnotationProcessor. (hereinafter referred to as APT)

Does APT only generate new Java files? Or is there a way to plug directly into the code to do what ASM does?

To keep you in suspense, let’s move on.

2. The apt and ButterKnife

Speaking of APT, ButterKnife has to be said.

The operation of generating XXX_ViewBinding through annotations became popular, and Javapoet became a household word.

To recap, here are the APt-related apis provided in the JDK.

Javax-annotation. Processing - AbstractProcessor // entry - ProcessingEnvironment // compiler environment, Application-filer // file read/write util-lang. model-element-element // code structure information -type- TypeMirror // Type information at compile time (very similar to Class, but that's run-time stuff, note that it's compile time)Copy the code

A normal annotation processor has these steps:

  1. inheritanceAbstractProcessor
  2. Get the correlation according to annotationsElement
  3. writeFiler
  4. inapp/build/generated/source/apt/The relevant Java files will be generated below

However, Filer is limited in that it has only create-related interfaces.

public interface Filer {
    JavaFileObject createSourceFile(CharSequence name, Element... originatingElements) throws IOException; . }Copy the code

We have to find another way.

3. Javac and rewrite AST

Let’s consider a question:

  1. AbstractProcessor. The process () the entrance is invoked by something?

The compiler, of course. In general, we use the Javac compiler.

For now, we just need to read through the javac source code (an overview of the Java compilation process) and see that the compilation process looks like this:

  1. Parse and Enter: Parse the.java file, generated in memoryAST (Abstract Syntax Tree),Fill symbol table
  2. Annotation Processing: callAbstractProcessor.process()If a new Java file is generated, go to Step 1
  3. Analyse and Generate: Sequential executionMark inspection,Data and control analysis,Title, method of sugar,Generates and writes to a. Class file

In this way, we know that our APT code executes step 2 in the Java compilation process.

If the compiling process is.java -> AST ->.class, then we can modify the AST intermediate in APT to change the final.class to achieve the same effect as ASM.

In particular, we need to use some internal Javac apis that are not part of the Java/or Javax/package of the JDK. It is in the com.sun.tools.javac/ of tools.jar and is no longer expanded.

AST for Android AOP: Abstract syntax tree

4. One example, one line of comment to get the singleton

Let’s say I have oneUserManager, trying to make it a singleton.

The original way of generating a new file will not work. But now we can insert code.

  1. Define a custom annotation@Singleton, and an annotation handlerSingletonProcessor
  2. Source code plus one line@Singleton:
// UserManager.java
@Singleton
class UserManager {}Copy the code

InstanceHolder = apt ();

// Build directory, userManager.class
@Singleton
class UserManager {

    public static UserManager getInstance(a) {
        return UserManager._InstanceHolder._sInstance;
    }

    UserManager() {
    }

    private static class _InstanceHolder {
        private static final UserManager _sInstance = new UserManager();

        private _InstanceHolder(a) {}}}Copy the code

Implementation details: github.com/fashare2015…

5. Afterword.

As a big fan of Java, I want to make some syntactic candy. So the Java-SUGAR project was tinkered with.

Several common design patterns such as singleton, Builder and observer are realized.

In addition to automatically generating getters and setters, Java should be as good as Kotlin (funny).

Maybe, roughly, copy all of Kotlin’s grammar candy?

6. Reference

Openjdk.java.net/groups/comp…

Java front-end compilation: The process of compiling Java source code into Class files

Javac Hacker guide

AST for Android AOP: Abstract Syntax tree

Lombok