Scala Advent Calendar 2016のAdventar版の22日目です。
空いていたのを見かけたので登録をさせてもらいました。
Macrooomというobject-object mapperのScalaのライブラリを先日作りましたので、そちらの紹介をさせていただきます。
Macrooomとは
MacrooomはScalaのマクロ機能を使って、あるクラスのインスタンスの値をマッピングして別のクラスのインスタンスを生成するためのライブラリです
Macro + OOM (Object-Object Mapper)ということでMacrooomという名前にしました。
開発をしていると、似たようなフィールドを持っているけど、違う目的のクラスを作ることがあると思います。
そのクラスのインスタンスを生成する際にフィールド数が少なければ自分でマッピングする処理を手動で書いても良いのですが、数が増えて来ると手作業で書くのが面倒になってきますし、後から新しくフィールドを追加した際にマッピング部分を更新するのを忘れてしまうこともあります。
Macrooomを使うことで、Scalaのマクロを利用して自動かつ高速にマッピングを実行できます。
同じくマクロを使ってマッピングをするライブラリとしてScala AutoMapperがあり、こちらはネストも扱ってくれますが、ケースクラスにしか対応をしていません。
Macrooomはネストには対応をしていませんが、Scalaの通常のクラスとJavaのクラスにも対応をしています。
使い方
以下のようにbuild.sbtのlibraryDependenciesに追加すれば利用できます。
libraryDependencies ++= Seq(
"com.github.h-kishi" %% "macrooom" % "0.2.0"
)
例えば、以下のような二つのクラスがあった時に、
case class SourceClass(id: Int, name: String)
case class TargetClass(name: String)
以下のように関数を定義することで、オブジェクトのマッピングが実行できます。
import macrooom._
// Convert from Scala object to Java object
def convert(src: SourceClass) = ObjectMapper.convertTo[SourceClass, TargetClass](src)
val source = SourceClass(1, "Name")
val target = convert(source)
source.name == target.name // true
上記のconvert
は実際にはマクロで以下のようなコードが作られています。
def convert(src: SourceClass) = new TargetClass(name = src.name)
また、以下のようなScalaのクラスとJavaのクラスもMacrooomを使ってマッピングすることができます。
class ScalaClass(val id: Int, val name: String)
class JavaClass {
private int id;
private String name;
public void setId(int id) { id = id; }
public int getName() { return id; }
public void setName(String name) { this.name = name; }
public String getName() { return name; }
}
注意する点としては、Scalaの場合はコンストラクタの変数名でマッピングをしますが、Javaの場合はデフォルトコンストラクタを使った後にアクセッサを利用して値をマッピングするようになっているので、それらが定義されていることが必須です。
(Javaだとマクロでコンストラクタの変数名が取れなかったため・・・)
参考にしたもの
元々は scalikejdbc の scalikejdbc-syntax-support-macro の autoConstruct
が便利だったので同じように実現できないかな、というところから作り始めました。
マクロの使い方もautoConstruct
の書き方を参考にさせてもらいました。
今回はMaven Central Repositoryに登録をしたのですが、その際のsbtファイルの書き方などは「Scalaで作成したライブラリをMavan Central Repositoryに登録する手順」を参考にさせてもらいました。
終わりに
私自身の用途としては、今関わっているプロジェクトでScalaのケースクラスをJavaのクラスへマッピングする必要があって使っています。
ニッチな用途向けになりそうですが、使えそうな場面がありましたら是非使ってみてください。
コード量が少ないので、Scalaのマクロに興味がある方はコードを見てみるとマクロを使うための参考になるかもしれません。