Table of Contents:
概要
大抵のORMは特定の型をシリアライズしてカラムに埋め込む機能があります。この機能を type adapterと呼ぶことにします。このtype adapterについて、既存のORMの実装とOrmaでの実装を紹介します。
たとえば、Google Play Services のLatLngなどはtype adapterを使ってカラムに埋め込むとすると、ORMに以下の情報を伝える必要があります。
- シリアライズ元の型(
LatLng
など) - シリアライズ先の型(
String
など) - DBのストレージ型(SQLiteの
TEXT
など) - シリアライズとデシリアライズをどのように行うか
実例
いくつか実例をみてみます。評価ポイントは、上記の情報をどうやって伝えるかと、type adapterをどのように使うかです。特に、動的にtype adapterを検索して呼び出すのか、静的に呼び出せるのかは実行速度に影響が出るので重要です。
GreenDAO
- Custom Types
- type adapterは
PropertyConverter<P, D>
を実装したクラスのインスタンス - 型とtype adapterの関係は静的に解決される
DBFlow
- Type Converters
@com.raizlabs.android.dbflow.annotation.TypeConverter
で注釈してcom.raizlabs.android.dbflow.converter.TypeConverter<DataClass, ModelClass>
を継承するとtype adapterにできる- packageの異なる同名の
TypeConverter
を使っているので非常に記述が煩雑。どうしてこうなった…。 - 型とtype adapterの関係は動的に解決される
ActiveAndroid
- Type serializers
- type adapterは
TypeSerializer
を継承したクラスのインスタンス - 型とtype adapterの関係は静的に解決される
Ormaでの実装
v1.0では、interface TypeAdapter<SourceType>
を実装したクラスを OrmaDatabase.Builder
に与えるという方式でした(dynamic type adapter
)。これは強制的にStringにシリアライズしていたので、バイナリを埋め込むことができませんでした。
そこでこれを改善すべくv1.2で実装したtype adaptersは、POJOに @StaticTypeAdapter
で注釈して静的メソッド serialize()
と deserialize()
を実装する方式にしました。
このtype adapterは、annotation processingで型とtype adapterの関係を静的に解決し、生成するコードにserialize()
やdeserialize()
の呼び出しが埋め込まれるというものです。SQLiteの適切な型とメソッド(たとえばBLOB
とCursor#getBlob()
)を扱えるようになったので、バイナリを埋め込めるようになりました。
Ormaの実装はさらにオブジェクトインスタンスを介さず静的メソッドを呼び出すので、実行速度の点で有利です。
実装例:
@StaticTypeAdapter( targetType = LatLng.class, serializedType = String.class ) public class LatLngAdapter { // SerializedType serialize(TargetType source) @NonNull public static String serialize(@NonNull LatLng source) { return source.latitude + "," + source.longitude } // TargetType deserialize(SerializedType serialized) @NonNull public static Location deserialize(@NonNull String serialized) { String[] values = serialized.split(","); return new LatLng( Double.parseDouble(values[0]), Double.parseDouble(values[1])); } }
v1.0のときの動的なtype adapterもまだ残していますが、2.0で削除予定です。そうなると、コンパイルタイムに適切なtype adapterがなければコンパイルエラーを出すようにできるはずです。