1. 序章

構成は、ソフトウェアアプリケーションの重要な部分です。 ただし、構成ファイルの解析と処理は、多くのボイラープレートコードを含む面倒なプロセスになる可能性があります。 このアプローチはエラーが発生しやすく、反復的です。 このチュートリアルでは、構成ファイルを操作するための小さくて効果的なScalaライブラリであるPureConfigを見ていきます。

2. PureConfigの利点

PureConfigを使用する利点のいくつかは次のとおりです。

  • 設定ファイルを読み取るためにボイラープレートコードは必要ありません
  • プロパティファイル、JSON、HOCONなどの複数の形式のサポート
  • カスタムタイプをサポートする機能
  • シンプルで直感的なAPI

3. 設定

プロジェクトでPureConfigを使用するには、最初にbuild.sbtファイルに依存関係を追加します。

libraryDependencies += "com.github.pureconfig" %% "pureconfig" % "0.17.1"

これで、ほとんどの基本操作をサポートできるimportステートメントを追加できます。

import pureconfig._
import pureconfig.generic.auto._

4. 構成ファイルのロード

4.1. application.confファイルから読み取る

まず、application.confファイルで簡単な構成を定義しましょう。

notification-url = "http://mynotificationservice.com/push"
params = "status=completed"

次に、この構成を保持するケースクラスを定義します。

final case class NotificationConfig(notificationUrl:String, params:String)

設定ファイルのキーはkebab-caseを使用しているのに対し、caseクラスはキャメルケースの後に続くことに注意してください。 これは、PureConfigのデフォルトの標準です。 ただし、この形式をカスタマイズすることは可能です。 それでは、設定ファイルをロードしましょう。

val notificationConfResult: ConfigReader.Result[NotificationConfig] = ConfigSource.load[NotificationConfig]

ConfigReader.Result のエイリアスです [ConfigReaderFailures、NotificationConfig]のいずれか。 結果から構成値にアクセスするには、次のようにします。

val params = notificationConfResult.right.get.params
params shouldBe "status=completed"

次のように、application.confファイルの特定のノードから構成値を読み取ってロードすることもできます。

kafka {
    port = 8090
    bootstrap-server = "kafka.mydomain.com"
    protocol = "https"
    timeout = 2s
}

これを行うには、構成値を保持する対応するケースクラスを定義します。

final case class Port(number: Int) extends AnyVal
final case class KafkaConfig(
  bootstrapServer: String,
  port: Port,
  protocol: String,
  timeout: FiniteDuration
)

これで、構成値を次のようにロードできます。

val kafkaConf = ConfigSource.default.at("kafka").load[KafkaConfig]

これにより、kafkaノードの構成値がapplication.confファイルからKafkaConfigケースクラスにロードされます。

4.2. カスタム構成ファイルから読み取る

PureConfigは、カスタムファイルから構成値を読み取ることもできます。 notification.conf という名前のファイルから構成値をロードするには、次を使用できます。

val notificationConf = ConfigSource.resources("notification.conf").load[NotificationConfig]

4.3. 文字列コンテンツから読み取る

構成値がStringとして使用できる場合は、次のように構成クラスにロードできます。

val notificationConfStr = ConfigSource.string("""{"notification-url": "https://newURL", "params":"status=pending"}""")

4.4. 失敗時に例外をスローする

デフォルトでは、PureConfigは構成の読み取りに失敗しても例外をスローしません。 代わりに、エラー情報を含むLeft値を含むEither結果を返します。 ただし、場合によっては、例外をスローしてすぐに失敗する方がよい場合があります。 これを行うには、構成のロード中にloadOrThrowメソッドを使用します。

val conf = ConfigSource.string("""{"notification-u": "https://wrongURL", "params":"status=pending"}""").loadOrThrow[NotificationConfig]

5. カスタマイズ

5.1. 構成フィールド形式のカスタマイズ

デフォルトでは、PureConfigはkebab-caseの構成キーとcamel-caseのcaseクラスフィールドを想定しています。 「ヒント」を提供することで、デフォルトの動作をカスタマイズできます。 PureConfigは、Pascalケース、Snakeケース、ScreamingSnakeCaseなどの他の形式をサポートしています。 必要な形式を暗黙のヒントとして定義できます。

implicit def hint[A] = ProductHint[A](ConfigFieldMapping(CamelCase, CamelCase))

これで、PureConfigは、構成キーとケースクラスフィールドの両方が CamelCaseにあることを期待します。

5.2. 日付形式のカスタマイズ

コンバーターを使用して、構成で必要な日付形式を定義できます。

implicit val localDateConvert = localDateConfigConvert(DateTimeFormatter.ISO_DATE)
implicit val localDateTimeConvert = localDateTimeConfigConvert(DateTimeFormatter.ISO_DATE_TIME)

6. カスタムタイプの使用

PureConfigは、構成値のさまざまなタイプをサポートします。 String Int Double FinishDuration UUID などのタイプを読み取ることができますLocalDate。 これらとは別に、 PureConfigは、 Enumeratum JodaTime Circeなどの他の一般的に使用されるタイプの統合をすでに提供しています。

6.1. PureConfig統合を使用する

構成にEnumeratumタイプを使用する方法を見てみましょう。 まず、統合ライブラリの依存関係を追加する必要があります。

libraryDependecies += "com.github.pureconfig" %% "pureconfig-enumeratum" % "0.17.1"

次に、必要な構成を作成できます。

app-name = "baeldung"
env = Prod
baseDate = "2022-01-02"

フィールドenvEnumeratumの値をProdおよびTestとして設定する必要があります。 次に、Enumeratumタイプを定義しましょう。

sealed trait Env extends EnumEntry
object Env extends Enum[Env] {
  case object Prod extends Env
  case object Test extends Env
  override val values = findValues
}
final case class BaseAppConfig(appName: String, baseDate: LocalDate, env: Env)

これで、構成値のロードを使用できます。

import pureconfig.module.enumeratum._
implicit def hint[A] = ProductHint[A](ConfigFieldMapping(CamelCase, CamelCase))
val baseConfig = ConfigSource.default.load[BaseAppConfig]

6.2. カスタムタイプを使用

PureConfigでカスタムタイプを使用することもできます。 構成用の封印されたトレイトADTを処理する方法を見てみましょう。 まず、ADT構造を定義できます。

sealed trait Protocol
object Protocol {
  case object Http extends Protocol
  case object Https extends Protocol
}

次に、封印されたトレイトのリーダーを定義する必要があります。

implicit val protocolConvert: ConfigReader[Protocol] = deriveEnumerationReader[Protocol]

その結果、PureConfigは構成内のタイプHttpまたはHttpsを処理できるようになります。

7. 結論

このチュートリアルでは、PureConfigを使用した構成の処理について説明しました。 いつものように、ここで使用されるコードサンプルは、GitHubから入手できます。