名前付き区分値の自動生成(namedcls)

名前付き区分値とは?

名前付き区分値は、DBの区分値にて定義されない、とある業務ドメインに特化したスコープを自由に決められる区分値です。

例えば、RemoteApi呼び出しをするときの、リモート側の区分値を定義するのに利用されたりします。 リモート側の区分値は、厳密にはアプリのものとも言えず、特定の業務スコープを持っています。 そういう場合は、アプリ区分値(appcls)を使うよりも、名前付き区分値でカテゴライズしてあげたほうが良いでしょう。

業務ドメイン区分値って名前にした方が良かったかも...ってちょっと思ったりしています。

アプリ区分値とはどう違う?

アプリ区分値と似ていますが、アプリ区分値はあくまで、とあるアプリプロジェクト (maihama-docksideなど) という業務ドメインに特化した固定的な区分値です。名前付き区分値は、どういった領域を表現するか自由に決められます。 (アプリ区分値は、名前付き区分値の一種と言えます)

また、アプリ区分値はcommonプロジェクトでは利用できませんので、アプリをまたがる場合は自然と名前付き区分値になります。 これは、アプリをまたがるようなものは名前を特定してカテゴライズしたもので表現した方がわかりやすいだろう、という考えのもとにそうしています。

LastaFluteではどうしてる?

LastaFluteでは、lastafluteMap.dfprop に namedcls を指定して自動生成します。

DBFluteの区分値のクラス CDef と同じように、[自由な名前]CDef というクラスが自動生成され、DBの区分値と同じような形で利用ができます。 Classificationインターフェースをimplementsしています。

また、DBの区分値との連携もできます。要素の定義をするときにDBの区分値を指定して、関連付けさせることができます。 そうすることで、定義の冗長化を防ぐとともに、DBFluteのCDefとの変換メソッドが付与されるなど、よりスムーズな実装が可能です。

名前付き区分値の作り方

まったくゼロの状態から作成する手順は以下の通りです。(1,2は最初の一回だけなので、二個目以降は3から)

  • 1. lastafluteMap.dfprop に namedcls を追加
  • 2. [app]_[name]_cls.dfprop を作成
  • 3. dfpropで名前付き区分値を定義
  • 4. FreeGenを叩いてCDefを自動生成
  • 5. 自動生成された[Name]CDefをプログラムで利用

1. lastafluteMap.dfprop に namedcls を追加

最初の一回だけです。lastafluteMap.dfprop の freeGenList に namedcls を追加します。 (Exampleからスタートアップした場合は、大抵最初から定義されているので、多くの場合は不要なステップです)

commonプロジェクトとアプリプロジェクトそれぞれに定義します。 (使わないところでは指定しなくてもいいですが、どこで動いてどこで動かないとかになりがちなので、使う場合はすべてに指定してしまって良いでしょう。もしくは、commonだけにするとか...)

e.g. Maihamaプロジェクトの lastafluteMap.dfprop @lastafluteMap.dfprop
map:{
    # your service name, camel case, initial uncapitalised
    ; serviceName = maihama

    # package for your domain name, e.g. com.example
    ; domainPackage = org.docksidestage

    # settings for common project of all web applications
    ; commonMap = map:{
        ; path = ..
        ; freeGenList = list:{ env ; config ; label ; message ; mail ; template ; doc ; namedcls }
        ; propertiesHtmlList = list:{ env ; config ; label ; message }
    }

    # settings for web applications
    ; appMap = map:{
        ; dockside = map:{
            ; path = ../../maihama-dockside
            ; freeGenList = list:{ env ; config ; label ; message ; mail ; template ; html ; doc ; appcls ; namedcls }
            ; propertiesHtmlList = list:{ env ; config ; label ; message }
        }
        ; hangar = map:{
            ; path = ../../maihama-hangar
            ; freeGenList = list:{ env ; config ; label ; message ; mail ; template ; doc ; appcls ; namedcls }
            ; propertiesHtmlList = list:{ env ; config ; label ; message }
        }
    }

    # you can override (several) default settings like this:
    #; overrideMap = map:{
    #    ; dockside.freeGen.mail.targetDir = ./playsql/data/mail
    #}
}

2. [app]_[name]_cls.dfprop を作成

commonプロジェクト、もしくは、アプリプロジェクトの src/main/resources 配下に namedcls というパッケージを作って、その下に [app]_[name]_cls.dfprop という名前のテキストファイルを作成します。[name] は小文字で指定します。(commonプロジェクトの場合、[app]はサービス名になります)

e.g. docksideプロジェクトでのseaという名前付き区分値のdfpropの置き場所 @Directory
src/main/resources
 |-namedcls
 |  |-dockside_sea_cls.dfprop
 |-...
e.g. 名前付き区分値のdfpropのひながた @[app]_[name]_cls.dfprop
# /---------------------------------------------------------------------------
# namedcls: (NotRequired - Default map:{})
#
# The definition of named classification.
#
# Specification:
# map: {
#     [classification-name] = list:{
#         ; map:{ topComment=[comment]; codeType=[String(default) or Number or Boolean] }
#         ; map:{ refCls=[projectName]@[DB classification name] ; refType=[included or exists or matches] }
#         ; map:{ code=[code]; name=[name]; alias=[alias]; comment=[comment] }
#     }
# }
#
# *The line that starts with '#' means comment-out.
#
map:{
}
# ----------------/

3. dfpropで名前付き区分値を定義

DBFluteのDB区分値の定義の仕方とほとんど同じです。

classificationDefinitionMap | DBFlute
e.g. アプリ区分値の定義、検索用の会員ステータス区分値 @[app]_[name]_cls.dfprop
# /---------------------------------------------------------------------------
# namedcls: (NotRequired - Default map:{})
#
# The definition of named classification.
#
# Specification:
# map: {
#     [classification-name] = list:{
#         ; map:{ topComment=[comment]; codeType=[String(default) or Number or Boolean] }
#         ; map:{ refCls=[projectName]@[DB classification name] ; refType=[included or exists or matches] }
#         ; map:{ code=[code]; name=[name]; alias=[alias]; comment=[comment] }
#     }
# }
#
# *The line that starts with '#' means comment-out.
#
map:{
    ; SearchMemberStatus = list:{
        ; map:{ topComment=MemberStatus for search condition ; codeType=String }
        ; map:{ code=FML; name=Formalized; alias=正式会員; comment=ちゃんとしてる }
        ; map:{ code=PRV; name=Provisinal; alias=仮会員; comment=ちゃんとしてない }
        ; map:{ code=WDL; name=Withdrawal; alias=退会会員; comment=ちゃんとできなかった }
        ; map:{ code=ALL; name=All; alias=すべて; comment=すべての会員ステータス }
    }
}
# ----------------/

アプリ区分値に関係のない機能 (isCheckImplicitSet, tableなど) は利用できません。

一方で、アプリ区分値固有の機能 (refClsなど) もあります。

4. FreeGenを叩いてCDefを自動生成

DBFlute の FreeGen (manage.sh 12) を叩きます。

すると、mylasta.appcls の下に AppCDef が自動生成されます。

5. 自動生成された[Name]CDefをプログラムで利用

DBの区分値と同じように利用することができます。

Classificationインターフェースをimplementsしているので、DBのCDefで利用できるフレームワークの仕組みのほとんどが、同じように利用できます。

DB区分値との連携

アプリ区分値と同じです。

commonとアプリの階層化?

common の namecls と、アプリの

TODO jflute commonはcommon、アプリはアプリ、階層化したい場合は、そもそも名前を変えましょう

迷ったらひとまずアプリ区分値で

名前付き区分値にすべきかどうか?最初からは、なかなかわからないものです。

迷ったら、ひとまずアプリ区分値で作っておいて、 複数のアプリ区分値を作っていくうちに業務ドメインがわかってきたり、アプリ間で使いたくなったりしたときに、 名前付き区分値に移行するとかでも良いでしょう。