Skip to content

Latest commit

 

History

History
108 lines (94 loc) · 5.57 KB

README.md

File metadata and controls

108 lines (94 loc) · 5.57 KB

Bolt License: MIT Version Nexus Version Maven Centraal

Requires Annotation and Plugin

Gradle plugin and Java annotation that checks (and fails the build if there are missing annotations) class fields for the annotations.

The main story of this plugin and the annotation started with the missing SerializedName annotations for network model classes. Because of the missing SerializedName annotation in the network model classes, our JSON serialization/deserialization operations were failing.

It is a developer mistake to forget some required annotation but this mistake can be avoidable with this annotation and the plugin.

Requires Annotation

Using the annotation processor

To use the annotation:

  • Add maven central repository mavenCentral().
  • Add dependency as an implementation and annotation processor:
implementation "eu.bolt:requiresannotation.annotation:1.2"
annotationProcessor "eu.bolt:requiresannotation.processor:1.2"
// lets declare both annotationProcessor and kapt of them https://issuetracker.google.com/issues/80270236
kapt "eu.bolt:requiresannotation.processor:1.2"

Configuring the Annotation using the plugin

You can use @RequiresAnnotation for the methods and the classes. For classes, it will also search for the required annotation in the defined method's parameters.

@RequiresAnnotation(requires = [ANNOTATION_CLASS_ARRAY], ignore = [CLASS_ARRAY])
  • requires: Annotations that at least one of them is required in the parameters of this class' methods.
  • ignore: Ignore the classes for required annotation checks.

Example use-case of the annotation

Let's assume that we have a class and we want every method parameter in this class should be non-null and should be annotated with @NonNull annotation

public class SomeClass {
    public void someStringMethod(String stringParam){}
    public void someIntegerMethod(@NonNull Integer integerParam){}
    public void someCustomClassMethod(MyClass integerParam){}
}

In this case someStringMethod's stringParam don't have @NonNull annotation. But on the other hand, inside this class we only accept someCustomClassMethod's MyClass parameter as a null. For informing the developer about missing annotation, we can fail the build using this annotation with following configruation:

@RequiresAnnotation(requires = [NonNull.class], ignore = [MyClass.class])

and we can place this annotation on the class. So the last version of the class will look like:

@RequiresAnnotation(requires = [NonNull.class], ignore = [MyClass.class])
public class SomeClass {
    public void someStringMethod(String stringParam){}
    public void someIntegerMethod(@NonNull Integer integerParam){}
    public void someCustomClassMethod(MyClass integerParam){}
}

When we start the build, it will be failed because of the someStringMethod and it will ignore the someCustomClassMethod because of the ignored MyClass.

Requires Annotation Plugin

Using the plugin

The plugin of the annotation allows you to use other annotations also for the check. To use the plugin, you must first apply it and then configure the parameter described below. To apply the plugin in the

  • Add maven central repository mavenCentral() to the buildscript in the root project's build.gradle
  • Add dependency classpath "eu.bolt:requiresannotation.plugin:1.2" to the buildscript in the root project's build.gradle
buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "eu.bolt:requiresannotation.plugin:1.2"
    }
}
  • Apply plugin apply plugin: 'requiresannotation.plugin' to module in the module's build.gradle

Configuring the Annotation using the plugin

You can configure Requires Annotation using this plugin from module's build.gradle file. With the configuration, the annotation processor can also process the other annotations.

requiresAnnotationProcessor {
  requires = ['TARGET_ANNOTATION_PACKAGE_NAME': ['REQUIRED_ANNOTATION_PACKAGE_NAMES']]
  ignore = ['IGNORED_PACKAGE_NAMES']
}

Example use-case of the plugin

Let's assume that we are using Retrofit library for the API calls.

@POST("/driverPhoneDetails")
Single<ServerResponse> sendSomeRequest(@Body SomeRequestModel body);

We want to fail the build if some of the fields in the SomeRequestModel class don't have SerializedName annotation.

data class SomeRequestModel(
    @SerializedName("string_field")
    val stringField: String,
    val intField: Int)

If we make an API call with this model, most probably it will fail on the release build because of the obfuscation causes the field name changes and the JSON serialization/deserialization library uses field names if JSON property name not given using the SerializedName annotation. In this case, there is a missing SerializedName annotation on the intField field.

So we need to check all the class fields used in the methods annotated with @POST for the @SerializedName annotation. Requires Annotation can do this check with the following configuration on the module's build.gradle file:

requiresAnnotationProcessor {
  requires = ['retrofit2.http.POST': ['com.google.gson.annotations.SerializedName']]
  ignore = ['com.example.MyIgnoreClass']
}