Help us understand the problem. What is going on with this article?

Scalaのobjec-object mapperライブラリ Macrooomの紹介

More than 3 years have passed since last update.

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のマクロに興味がある方はコードを見てみるとマクロを使うための参考になるかもしれません。

h_kishi
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした