0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Kotlin】Javaを前提としたリフレクションによるマッピングライブラリは基本的にKotlinで動かない

Last updated at Posted at 2020-09-12

ModelMapperなど、「Java向けのリフレクションを利用したマッピングライブラリがKotlindata classに対して機能しない」という話をしばしば見かけるので、何故そうなるのかと、それに対応するためにどのような手段が有るかを書きます。

TL;DR

  • Java向けのマッピングライブラリは「引数無しコンストラクタでインスタンス生成 -> 個々のフィールドを初期化」という手順を前提としている
  • 一方、Kotlindata classは基本的に引数無しコンストラクタを持たない
  • このため、Java向けのリフレクションを利用したマッピングライブラリはKotlindata classに対して機能しない

補足

この記事では、マッピングライブラリという言葉を以下のような意味で使います。

  • マッピングライブラリ: 何らかのソースからフィールドを初期化したオブジェクトインスタンスを生成するような機能を提供するライブラリ
    • e.g. ModelMapper, BeanPropertyRowMapper

また、Kotlin上のマップ先はclassでもdata classでも関係有りませんが、data classになる場合が多いだろうということで、この記事内ではdata classを前提として扱います。

本文

  • デコンパイルしてみる
  • 無理やりでも動かす
  • Kotlinに対応したツールについて

デコンパイルしてみる

data classは引数無しコンストラクタを持たない」を確認するため、以下のクラスをideaの機能でデコンパイルしてみます。

data class Sample(val foo: Int, val bar: Int?)

結果は以下のようになります。
引数無しコンストラクタの定義が無いことが分かります。

デコンパイル結果(※記事内容に関係の無い部分は省略済み)

/* 略 */

public final class Sample {
   private final int foo;
   @Nullable
   private final Integer bar;

   public final int getFoo() {
      return this.foo;
   }

   @Nullable
   public final Integer getBar() {
      return this.bar;
   }

   public Sample(int foo, @Nullable Integer bar) {
      this.foo = foo;
      this.bar = bar;
   }

   /* 略 */

無理やりでも動かす

ここまでで説明した通り、Java向けのリフレクションを利用したマッピングライブラリはKotlindata classに対して機能しません。
ただ、無理やりにでも動かす方法は幾つか有ります。

No-arg compiler pluginを使う

Kotlin公式で、実行時にのみ呼び出せる引数無しコンストラクタを追加するプラグインが提供されています。
これを用いることで、null安全は壊れるものの、見かけ上は従来のライブラリが機能するようになります。

引数無しコンストラクタをKotlin上に書く

マップ先クラスをJavaPOJOっぽく機能するように書けば従来のライブラリが機能するようになります。
また、外部に公開するインターフェースと実際のデータを入れるクラスの実装を分離すれば、「外から見る限り普通のdata classっぽく見える」状況は実現できます。

完全なKotlin化を諦めるなら、POJOで実装した上でゲッターにNullabilityを表すアノテーションを付けるというのも手です。

Kotlinに対応したライブラリについて

最後に、自分が把握している限りでKotlinに対応したObject to Objectマッピングライブラリに関して書きます。

KMapper

筆者が作成した、Kotlinのリフレクションによる関数呼び出しベースのマッピングライブラリです。
Object以外にも、Mapなどを引数に取ったり、複数引数からマッピングを行うことができます。

自作する

Kotlinのリフレクションによる関数呼び出しは割と簡単に実装できるため、機能性を求めなければサクッと自作してしまうのが簡単という気がしています。

MapStruct

記事執筆時点ではベータ版ですが、MapStruct1.4からコンストラクタ呼び出しによるマッピングをサポートするそうです。

補足として、詳しい話は省きますが、annotation-processorベースのライブラリであればJava向けのものでも原理的にKotlin対応がしやすいのかなと思っています。

Jackson

JacksonにはKotlinサポートが有るため、これによって「1度JSON化する -> デシリアライズする」という手順でマッピングが実現できます。
機能は非常に充実していますし、シリアライズさえできれば多様なソースにも対応できることから、実行速度を除けばJacksonを用いるのが案外よいかもしれません。


この記事が英訳されて無断転載されていることを確認したため、各所に問い合わせ中です。
52e58e2f6d8b414c064258bf38fefe10c232a07a63263d33b2f26352cf22be8a

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?