Creating an AndroidAnnotations plugin - WonderCsabo/androidannotations GitHub Wiki
Before creating a plugin, ask the AndroidAnnotations developers first. We may want to include your new annotation(s) in AA core.
Creating an AndroidAnnotations plugin
Since AndroidAnnotations 4.0.0, you can easily add new annotations by creating plugins. Please note that plugins can only allow to add new annotations, not to modify behaviour of existing ones, or add new parameters to them.
Structure
A typical plugin will consist of two modules, just like AndroidAnnotations core:
- an API jar, which contains the annotations,
- the processor jar, which will process the annotations and generate the code:
- depend on the API jar
- depend on
org.androidannotations:androidannotations
You can create these with the build system of your choice, but you may want to look at one of AA's core plugins as an example.
You must choose a name for your plugin, which should be unique, so it can be found in the classpath without problems.
In these modules, you have to include some meta-data so the main AndroidAnnotations processor can find and invoke your plugin:
- in the API jar, add a resource named
{pluginname}-api.properties
(like this), - in the processor jar, add a resource named
{pluginname}.properties
(like this).
Substitute pluginname
with the real name of your plugin. Both of these files should have this content:
version=YOUR_VERSION
Substitute YOUR_VERSION
with the real version of your plugin, which should be for example the Maven version of the artefact.
Create the service descriptor file in your processor module, named META-INF/services/org.androidannotations.plugin.AndroidAnnotationsPlugin, like this. It should contain one line, the fully qualified class name of your plugin class:
com.example.YourPlugin
Creating your annotations
In the source folder of the api module, you can create your annotations. A source file for an annotation should look like this one:
/**
* Overrides toString() in the generated class.
*/
@Retention(RetentionPolicy.CLASS) // required
@Target(ElementType.TYPE) // this can vary per annotation
public @interface ToString {
}
Creating your processor
First, you have to create the entry point class of your plugin, which should inherit from AndroidAnnotationsPlugin
:
package com.example;
import java.util.ArrayList;
import java.util.List;
import org.androidannotations.AndroidAnnotationsEnvironment;
import org.androidannotations.handler.AnnotationHandler;
import org.androidannotations.plugin.AndroidAnnotationsPlugin;
// the same class declared in the service descriptor file
public class YourPlugin extends AndroidAnnotationsPlugin {
@Override
public String getName() {
return "pluginname"; // the same name used in your .properties files
}
@Override
public List<AnnotationHandler<?>> getHandlers(AndroidAnnotationsEnvironment androidAnnotationEnv) {
List<AnnotationHandler<?>> handlers = new ArrayList<>();
handlers.add(new ToStringHandler(androidAnnotationEnv));
// all the handlers which process your annotations
return handlers;
}
}
Then you can create the actual handler class which will validate and process your annotation:
package com.example;
import javax.lang.model.element.Element;
import org.androidannotations.AndroidAnnotationsEnvironment;
import org.androidannotations.ElementValidation;
import org.androidannotations.handler.BaseAnnotationHandler;
import org.androidannotations.holder.EComponentHolder;
import com.example.api.ToString;
import com.helger.jcodemodel.JExpr;
import com.helger.jcodemodel.JMethod;
import com.helger.jcodemodel.JMod;
public class ToStringHandler extends BaseAnnotationHandler<EComponentHolder> {
public ToStringHandler(AndroidAnnotationsEnvironment environment) {
super(ToString.class, environment); // this handles your @ToString annotation
}
@Override
protected void validate(Element element, ElementValidation validation) {
validatorHelper.enclosingElementHasEnhancedComponentAnnotation(element, validation);
// the annotation only can be used in an enhanced class
}
@Override
public void process(Element element, EComponentHolder holder) throws Exception {
JMethod toString = holder.getGeneratedClass().method(JMod.PUBLIC, getClasses().STRING, "toString");
toString.body()._return(JExpr.lit("Hello, AndroidAnnotations!"));
toString.annotate(Override.class);
// creates a method in the generated class:
// @Override
// public String toString() {
// return "Hello, AndroidAnnotations!";
// }
}
}
And that is it! With this minimal setup, you can process this class:
@EActivity
@ToString // your annotation
public class MyActivity extends Activity {
}
And you will generate this:
public class MyActivity_ extends MyActivity {
@Override
public String toString() {
return "Hello, AndroidAnnotations!";
}
// ...
}
Of course this is just a dummy example. For more complicated cases, please look at the source code of AndroidAnnotations.