APTでデータクラスからBundleに変換するクラスを自動生成してみた
経緯
Bundleにデータをセットするのがめんどい…
特にキー文字列の定義とか超めんどい…
Serialize、Parcelableとかも正直めんどい…
具体的にはこんな感じ↓↓↓の作業…めんどい…
final Bundle args = new Bundle();
args.putInt("key_id", value.getId());
args.putString("key_tag", value.getTag());
args.putBoolean("key_enabled", value.isEnabled());
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");
やりたいこと
AutoValue的な感じでAnnotation付けるだけでBundleに変えてくれる、Bundleから値を取り出せるようなクラスが自動作成されるとかしたい。具体的には、Annotation Processsing Tool
を使って以下の要件を満たすようなクラスを自動生成したい。
- データクラスに保存したい値にアノテーションを付けてビルドすると自動クラスが生成される
- データクラスを自動生成したクラスに渡すとBundleに変換される
- 変換したBundleを再び自動生成したクラスに渡すと元のモデルクラスの値が取れる
実装イメージ
データクラスに保存したい値にアノテーションを付けてビルドすると自動クラスが生成される
@BundleGenerator // クラスを指定
public class Sample {
private final int mId;
public Sample(int id) {
mId = id;
}
@BundleSet // 値を指定
public int getId() { return mId; }
}
ビルドで以下のようなクラスが自動生成される。
// データクラス名 + BundleGenerator で自動生成
public class SampleBundleGenerator {
// モデルを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;
}
// 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");
}
}
}
データクラスを自動生成したクラスに渡すとBundleに変換される
Bundle bundle = SampleBundleGenerator.bundle(value);
変換したBundleを再び自動生成したクラスに渡すと元のモデルクラスの値が取れる
SampleBundleGenerator.Wrapper sample = SampleBundleGenerator.restore(getArguments());
成果物
とりあえず実装してみた結果はこちら→ github:BundleGenerator
APT実装方法
詳細は他の記事でもアップされているので大まかな流れだけ紹介。
(1)AndroidStudioで新規プロジェクトを作成(普通にアプリを作る感じ)
(2)新規モジュールで「java library」を追加(モジュール名を processor とかにすると分かりやすい)
(3)ライブラリ側にAbstractProcessorを継承したクラス、及び使用させたいアノテーションのクラスを作る(Processorクラスにてコンパイル時にアノテーションを付けた要素を見つけて実現したいクラスを自動生成する)
@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) {
// ここでクラスを生成する
// 引数のroundEnvから、お目当のアノテーションに該当するElementを取り出して、その情報を使ってクラスを生成する
// JavaPoetというライブラリを使うとクラス作成が非常に楽にできる
}
}
(4)javacがフックできるようにProcessorのエントリポイントを定義する。
以下にjavax.annotation.processing.Processor というファイルを作成し、作成したアノテーションプロセッサのクラス名を記述する(上記だと abj.bundlegenerator.processor.BundleGeneratorProcessor )
(5)使用したいモジュール側にライブラリを定義する
dependencies {
implementation project(':processor')
annotationProcessor project(':processor')
}
参考
https://qiita.com/LyricalMaestro0/items/9a4e3ec3ea7bda9ee523
https://qiita.com/opengl-8080/items/beda51fe4f23750c33e9
https://qiita.com/shiraji/items/ed674c5883ed0520791b
Author And Source
この問題について(APTでデータクラスからBundleに変換するクラスを自動生成してみた), 我々は、より多くの情報をここで見つけました https://qiita.com/jabachan/items/b5a4dd7fbbae7c5539e1著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .