Android builds compile-time annotation parsing framework It's just a start.

Source: Internet
Author: User

Reprint please indicate source:, this article from: "Zhang Hongyang's Blog"
1. Overview

Remember a long time ago, wrote a few blog, let me enumerate:

Android advanced teach you to build the IOC framework "Viewinject" (above) in Android

Android advanced teach you to build the IOC framework "Viewinject" in Android (bottom)

Android framework to teach you how to write inter-component communication framework Eventbus

We can pay attention to these blog comments, no matter how, we have a lot of performance considerations, a see this kind of framework, do not parse fortunately, as long as the interpretation is the annotation and reflection, the inevitable problem is: this will affect the performance AH? Well, there's going to be a loss of performance, so I'll think about a better way to do it? can be injected, but also to ensure that performance without loss? The good news is, yes, yes, the above-mentioned blog implementation, including Xutils, afinal the current injection using the runtime annotations, of course, there is a class of annotations called compile-time annotations.

2. Annotations

said the annotation, unexpectedly still have various classification, has, this cannot remember, we from the function of the annotation to push its classification, helps everybody to remember, then strengthens everybody's memory, say the annotation function:

1, mark some information, so that may be too abstract, then I said, you have seen @override, @SuppressWarnings, etc., such annotations are used for identification, can be used as a test

2, the runtime dynamic processing, this people should see the most, at run time to get the class object, and then traverse its methods, variables, to determine whether there is no annotation statement, and then do something. Similar to the practices in the three blog posts above.

3, compile-time dynamic processing, this? is our main character today, generally this kind of annotations will be compiled at the time, according to the annotations identified, dynamically generate some classes or generate some XML can, at runtime, such annotations are not ~ ~ will rely on dynamically generated classes do some operations, because there is no reflection, efficiency and direct call method is no different ~ ~ ~

About 3, we do not understand, nothing, the following will be discussed in detail, the use of such annotations items are: Parcelablegenerator, Butterknief, androidannotaion and so on.

The role is over, so if you see an annotated statement how do you judge his role? For example:

@Retention (Retentionpolicy.class) @Target ({Elementtype.field, elementtype.type}) public @interface Injectview{int Value ();}

1 seconds tell me, what does it do? Ha, everyone may be depressed, rub, how I know. In fact, you can see this annotation above the value of the @retention, set to class, the description is compiled at the time of dynamic processing.

This value is an enumeration: There are three: SOURCE, RUNTIME, CLASS, here, is not, search karma, these three 11 corresponds to the above three functions.

Well, the function of the annotations and the way of judging, then you can see that in addition to @retention there is a @target, @Target value is a elementtype[] array. What do you mean? is to indicate what this annotation can identify, such as classes, variables, methods, and even annotations themselves (meta annotations). This is in: Android Advanced teach you to build the IOC framework in Android "Viewinject" (above) is described in detail.

Well, to this note, you just have to remember the function of the annotation and how to define an annotation.

Next go to our topic compile-time annotations.

By the way, I created a public number, will push some open-source projects, the latest blog, video, etc., about the blog involved in things, will be notified in advance, you can pay attention to, thank you, the left column, scan can.

3. Compile-time annotations

Let's talk about the writing process.

1. Create a class that inherits Abstractprocessor

Package Com.zhy.util.ioc.processor;import Java.util.set;import Javax.annotation.processing.AbstractProcessor; Import Javax.annotation.processing.roundenvironment;import javax.annotation.processing.SupportedAnnotationTypes; Import Javax.annotation.processing.supportedsourceversion;import Javax.lang.model.sourceversion;import javax.lang.model.element.TypeElement; @SupportedAnnotationTypes ("Com.zhy.util.ioc.annotation.InjectView") @ Supportedsourceversion (sourceversion.release_6) public class Viewinjectprocessorbeta extends abstractprocessor{@ Overridepublic Boolean process (set<? extends typeelement> annotations,roundenvironment roundenv) {//TODO Auto-generated method Stubreturn false;}}

You can add annotations on this class:

The @SupportedAnnotationTypes value is the full classpath for annotations supported by the current class, and wildcard characters are supported.

@SupportedSourceVersion identify the source version supported by the processor

In addition, there is a @supportedoptions, this is usually the command line when used, set some options, but, command line I am not familiar with, so: slightly.

Note: If you can not find abstractprocessor, remember to right-click Build-path Add Library to add the JDK.

2, create resources and other documents.

This has a fixed requirement for a structure of the project, which I'll use as a graph:

As you can see, in our project, we also need to create a source folder such as resources, and right-click New Sources folder.

Then create the Meta-inf/services/javax.annotation.processing.processor file inside, which writes the complete path to our processor's class.

After the above two, our authoring environment is OK.

4. Complete Example

Let's take an example to show you the compile-time dynamic generation of data, our effect is that the user writes a bunch of beans, such as the user class, we dynamically generate a JSON file through the annotation extraction property, and a proxy class, note that it is generated at compile time.

Note: The following is an example of teaching, without any use value.

Then we are still divided into steps to do:

1. Create the authoring environment

Javax.annotation.processing.Processor is written in: Com.zhy.annotationprocess.processor.BeanProcessor

We also created an annotation:

Package Com.zhy.annotationprocess.annotation;import Java.lang.annotation.elementtype;import Java.lang.annotation.retention;import Java.lang.annotation.retentionpolicy;import java.lang.annotation.Target;@ Target ({Elementtype.field, elementtype.type}) @Retention (retentionpolicy.class) public @interface seriable{}

Ha, a second to tell me, what kind of function of the annotations.

2, dynamic generation of data

1, first clear our goal:

We have a lot of bean classes, such as:

public class user{@Seriableprivate string username; @Seriableprivate string Password;private string Three;private string Four;}

@Seriablepublic class Article{private string title; private string Content;}

See there are two ordinary beans, which declares our annotations, and if we declare annotations on a class we generate a JSON descriptor for all of its variables, and if it is just a member variable? Then we only extract the declared member variables to generate dynamically.

A description file similar to the following:

{class: "Com.zhy.Article", fields: {  content: "Java.lang.String",  title: "Java.lang.String"}}

Do not feel useless, in fact, the use of large drops, we will verify later.

2, Write Beanprocessor

Package Com.zhy.annotationprocess.processor;import;import;import;import java.util.arraylist;import java.util.hashmap;import Java.util.List;import java.util.Map ; Import Java.util.set;import Javax.annotation.processing.abstractprocessor;import Javax.annotation.processing.processingenvironment;import Javax.annotation.processing.roundenvironment;import Javax.annotation.processing.supportedannotationtypes;import javax.annotation.processing.SupportedSourceVersion; Import Javax.lang.model.sourceversion;import Javax.lang.model.element.element;import Javax.lang.model.element.elementkind;import Javax.lang.model.element.typeelement;import Javax.lang.model.element.variableelement;import Javax.lang.model.util.elementfilter;import Javax.lang.model.util.elements;import com.zhy.annotationprocess.annotation.Seriable; @SupportedAnnotationTypes (" Com.zhy.annotationprocess.annotation.Seriable ") @SupportedSourceVersion (sourceversion.release_6) public class BeanProcessor extends abstractprocessor{//element operation auxiliary class elements elementutils; @Overridepublic synchronized void Init ( Processingenvironment processingenv) {super.init (processingenv);//auxiliary class for element operation Elementutils = Processingenv.getelementutils ();} @Overridepublic Boolean process (set<? extends typeelement> annotations,roundenvironment roundenv) {// Get the element set&lt that is declared by the annotation; Extends element> Elememts = Roundenv.getelementsannotatedwith (Seriable.class); Typeelement classelement = null;//declares the class element list<variableelement> fields = null;//declares a list of member variables to hold//store both map<string, list<variableelement>> maps = new hashmap<string, list<variableelement>> ();//Traverse for (Element ele: ELEMEMTS) {//Determines whether the element is a class if (ele.getkind () = = Elementkind.class) {classelement = (typeelement) ele;maps.put ( Classelement.getqualifiedname (). toString (), fields = new arraylist<variableelement> ());} else if (ele.getkind () = = Elementkind.field)//Determines whether the element is a member variable {variableelement Varele = (variableelement) ele;//Gets the element encapsulation type T YpEelement enclosingelement = (typeelement) varele.getenclosingelement ();//get keystring key = Enclosingelement.getqualifiedname (). toString (); fields = Maps.get (key), if (n = null) {maps.put (key, fields = new Arraylist<variableelement> ());} Fields.Add (Varele);}} For (String Key:maps.keySet ()) {if (Maps.get (key). Size () = = 0) {typeelement typeelement = elementutils.gettypeelement ( Key); list<? Extends element> allmembers = elementutils.getallmembers (typeelement); if (allmembers.size () > 0) {maps.get (key). AddAll (Elementfilter.fieldsin (AllMembers));}} Generatecodes (maps); return true;} private void Generatecodes (map<string, list<variableelement>> maps) {file Dir = new File ("F://apt_test"); (!dir.exists ()) dir.mkdirs ();//Traverse Mapfor (String key:maps.keySet ()) {//create file = ' new ' (Dir, key.replaceall ("\ \"). "_") + ". txt"); try{/** * Write JSON file contents */filewriter FW = new FileWriter (file) fw.append ("{"). Append ("Class:"). Append ("\" "+ key +" \ ""). Append (", \ n"); Fw.append ("fields:\n {\ n "); list<variableelement> fields = Maps.get (key), for (int i = 0; i < fields.size (); i++) {variableelement field = Fiel Ds.get (i); Fw.append (""). Append (Field.getsimplename ()). Append (":"). Append ("\" + Field.astype (). toString () + "\" "); if (I < fields.size ()-1) {Fw.append (","); Fw.append ("\ n");}} Fw.append ("\ n}\n"); Fw.append ("}"); Fw.flush (); Fw.close ();} catch (IOException e) {e.printstacktrace ();}}}}

The code is a little bit long, but the comments are clear, and I'll explain that basically there are two processes: 1, identify the class or member variable that identifies the annotation, encapsulate it in maps, and 2, traverse maps to create a JSON file for each class. We have exported the file to the F://apt_test folder, if you do not have the F-disk God horse, modify the directory yourself.

3. Use

To this, we finished writing ~ ~ So how to use it?

1. Export jar

For a better demonstration, and save space, I recorded GIF

Note Some of the check boxes that I selected, and some of the default check boxes, I put them on the desktop ~ ~

2. Create a new Android or Java project

Copy the jar to Libs, and if it is a Java project, you need to create the Lib folder yourself and manually reference it yourself.

Then start writing the bean: I've written two classes here, a user, a article, and put a code on it.

3. Enable annotation processor

Here I am eclipse, if you are a MAVEN project or some other IDE, self-search web, there is an Android studio under the use of their own click Ha, in fact, the command line can also.

Below we eclipse is still a GIF, otherwise we have to cut a bunch of pictures:

Assuming that our jar has been copied to the project, do the following

After the operation is complete, then you can go to the f://apt_test

Open to see:

{class: "Com.zhy.User", fields: {  username: "java.lang.String",  Password: "Java.lang.String"}}

{class: "Com.zhy.Article", fields: {  content: "Java.lang.String",  title: "Java.lang.String"}}

OK, so, we have a simple annotation processor tutorial will be done ~ ~ If you want to learn, must go to try, all kinds of test, do not worry about trouble, if simple who will, that there is no meaning ~

This is a very simple example, so how do we use it specifically in our project? Given the length, it may be possible to continue in the next article. But the prototype of the library has been formed:

5, Hyviewinject

OK, this is based on a library, mainly for Android control injection, similar to Butterknief, is still in perfect, welcome to use, fork or star, we improve together.


The first activity in a TextView and ListView, the second activity of a textview and Fragment, mainly tests the activity, Fragment, adapter injection control.

GitHub Address: Click to send, is still in perfect, welcome to use, fork or star, we improve together.

Group number: 423372824

Bo Master part of the video has been online, if you do not like boring text, please poke (first record, look forward to your support):

Video Directory Address: I recorded a video tutorial

Android builds a compile-time annotation parsing framework This is just the beginning

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.