[JAVA] I tried to automatically generate a class to convert from a data class to a Bundle with APT

Background

It's a pain to set data in Bundle ... Especially the definition of the key string is super annoying ... To be honest, Serialize and Parcelable are annoying ...

Specifically, it looks like this ↓ ↓ ↓ work ... It's annoying ...

Work to pack values in Bundle


final Bundle args = new Bundle();
args.putInt("key_id", value.getId());
args.putString("key_tag", value.getTag());
args.putBoolean("key_enabled", value.isEnabled());

Fragment of values from Bundle


final Bundle args = getArguments();
final int id = args.getInt("key_id");
final String tag = args.getString("key_tag");
final boolean isEnabled = args.getBoolean("key_enabled");

Thing you want to do

I want to automatically create a class that can retrieve a value from a Bundle that changes it to a Bundle just by adding Annotation like AutoValue. Specifically, I would like to use ʻAnnotation Processsing Tool` to automatically generate a class that meets the following requirements.

--Automatic class is generated when you build by annotating the value you want to save in the data class --If you pass the data class to the automatically generated class, it will be converted to Bundle. --If you pass the converted Bundle to the automatically generated class again, you can get the value of the original model class.

Implementation image

Annotate the value you want to save in the data class and build it to generate an automatic class

Sample (model class)


@BundleGenerator //Specify class
public class Sample {
 
    private final int mId;
 
    public Sample(int id) {
        mId = id;
    }
 
    @BundleSet //Specify a value
    public int getId() { return mId; }
}

The following classes are automatically generated in the build.

SampleBundleGenerator (automatically generated class)


//Data class name+Automatically generated by BundleGenerator
public class SampleBundleGenerator {
    //Method to convert model to Bundle
    @NonNull
    public static Bundle bundle(@NonNull Sample target) {
        return bundle(target, new Bundle());
    }
  
    @NonNull
    public static Bundle bundle(@NonNull Sample target, @NonNull Bundle bundle) {
        bundle.putInt("xxx.xxx.Sample_getId", target.getId());
        return bundle;
    }
 
    //Method to retrieve value from Bundle
    @NonNull
    public static Wrapper restore(@NonNull Bundle bundle) {
        return new Wrapper(bundle);
    }
 
    public static class Wrapper {
        final Bundle mBundle;
 
        BundleWrapper(@NonNull Bundle bundle) {
            mBundle = bundle;
        }
 
        public int getId() {
            return mBundle.getInt("xxx.xxx.Sample_getId");
        }
    }
}

If you pass the data class to the automatically generated class, it will be converted to Bundle.

Set data in Bundle


Bundle bundle = SampleBundleGenerator.bundle(value);

If you pass the converted Bundle to the automatically generated class again, you can get the value of the original model class.

Fetch values from Bundle


SampleBundleGenerator.Wrapper sample = SampleBundleGenerator.restore(getArguments());

Deliverables

Click here for the result of implementing it for the time being → github: BundleGenerator

APT implementation method

Details are posted in other articles, so only the general flow is introduced.

(1) Create a new project in Android Studio (like making an app normally)

(2) Added "java library" in a new module (it is easy to understand if the module name is processor)

(3) Create a class that inherits AbstractProcessor on the library side and a class of annotations that you want to use (in the Processor class, find the element annotated at compile time and automatically generate the class you want to realize)

@SupportedAnnotationTypes({
    "abj.bundlegenerator.processor.BundleGenerator",
    "abj.bundlegenerator.processor.BundleSet"})
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class BundleGeneratorProcessor extends AbstractProcessor {
 
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        //Generate a class here
        //Extract the Element corresponding to the desired annotation from the argument roundEnv and generate a class using that information.
        //Creating a class is very easy with a library called JavaPoet
    }
}

(4) Define the entry point of Processor so that javac can be hooked. Create a file called javax.annotation.processing.Processor below and describe the class name of the created annotation processor (abj.bundlegenerator.processor.BundleGeneratorProcessor in the above) metainf.png

(5) Define the library on the module side you want to use

build.gradle


dependencies {
    implementation project(':processor')
    annotationProcessor project(':processor')
}

reference

https://qiita.com/LyricalMaestro0/items/9a4e3ec3ea7bda9ee523 https://qiita.com/opengl-8080/items/beda51fe4f23750c33e9 https://qiita.com/shiraji/items/ed674c5883ed0520791b

Recommended Posts

I tried to automatically generate a class to convert from a data class to a Bundle with APT
I tried to generate a C language program source from cURL
I tried to create an API to get data from a spreadsheet in Ruby (with service account)
I tried to break a block with java (1)
I tried to get started with Spring Data JPA
I tried to make a program that searches for the target class from the process that is overloaded with Java
I tried to create a java8 development environment with Chocolatey
I tried to modernize a Java EE application with OpenShift.
[Rails] I tried to create a mini app with FullCalendar
I tried to convert a string to a LocalDate type in Java
I tried to create a padrino development environment with Docker
I tried upgrading from CentOS 6.5 to CentOS 7 with the upgrade tool
I tried to make a group function (bulletin board) with Rails
I tried to express the result of before and after of Date class with a number line
I tried to make a parent class of a value object in Ruby
[For beginners] I want to automatically enter pre-registered data in the input form with a selection command.
I tried to get started with WebAssembly
[iOS] I tried to make a processing application like Instagram with Swift
I tried to make a Web API that connects to DB with Quarkus
I tried to build a Firebase application development environment with Docker in 2020
I tried playing with BottomNavigationView a little ①
I tried to build Ruby 3.0.0 from source
I tried to implement ModanShogi with Kinx
I tried to create a portfolio with AWS, Docker, CircleCI, Laravel [with reference link]
I tried to implement a function equivalent to Felica Lite with HCE-F of Android
I tried to make a simple game with Javafx ① "Let's find happiness game" (unfinished)
[Java] I tried to connect using a connection pool with Servlet (tomcat) & MySQL & Java
I tried to get the distance from the address string to the nearest station with ruby
[Android] I tried to make a material list screen with ListView + Bottom Sheet
I tried to clone a web application full of bugs with Spring Boot
When I tried to use a Wacom tablet with ubuntu 20.04, I didn't recognize it.
I tried to convert JavaBean and XML with Jackson formatter XML in this era
Transform from a normal class to a lambda expression
I tried to make Basic authentication with Java
I tried to manage struts configuration with Coggle
I tried to manage login information with JMX
java I tried to break a simple block
I tried to develop a DUO3.0 study website.
Convert a string to a character-by-character array with swift
I tried hitting a Java method from ABCL
How to convert a solidity contract to a Java contract class
I tried to create a LINE clone app
I want to play with Firestore from Rails
I tried to develop a website to record expenses.
I tried to implement a server using Netty
How to automatically generate a constructor in Eclipse
I tried to create a shopping site administrator function / screen with Java and Spring
I tried to make a simple game with Javafx ① "Let's find happiness game" (unfinished version ②)
I tried to create a log reproduction script at the time of apt install
I called YouTube video from DB with haml and tried to embed and display it
[Azure] I tried to create a Java application for free ~ Connect with FTP ~ [Beginner]
A story I was addicted to when getting a key that was automatically tried on MyBatis
I tried what I wanted to try with Stream softly.
I tried to implement file upload with Spring MVC
I want to call a method of another class
I tried to implement TCP / IP + BIO with JAVA
I tried to develop a ramen shop sharing website.
I tried to decorate the simple calendar a little
I started MySQL 5.7 with docker-compose and tried to connect
I tried to create a Clova skill in Java
I want to monitor a specific file with WatchService