【トラブル】【Scala】SBTでのエラー/警告対応

■ はじめに

https://dk521123.hatenablog.com/entry/2023/01/25/000000

で「sbt-assembly」を使って、JARファイルの作成をした際に
エラーが出たので、対処方法を記載する
また、その過程で警告とかの対応方法も分かったのでメモ。

目次

【1】sbt-assemblyでJARファイル作成をした際のエラー
【2】警告「re-run with -deprecation for details」が表示
【3】警告「`in` is deprecated; migrate to slash syntax」が発生
【4】警告「method sonatypeRepo in class ResolverFunctions is deprecated」が発生

【1】sbt-assemblyでJARファイル作成をした際のエラー

https://github.com/jhole89/aws-glue-sbt-quickstart

をCloneし、「sbt assembly」でJarファイルを作ろうとした際に
以下「エラー内容」が発生した

エラーが発生した build.sbt

val projectName = "myproj"
val organization = "myorg"
val version = "1.0"
scalaVersion in ThisBuild := "2.12.14"

addCommandAlias(
  "sanity",
  ";clean ;compile ;test ;scalafmtAll ;scalastyle ;assembly"
)

lazy val root = (project in file("."))
  .disablePlugins(sbtassembly.AssemblyPlugin)
  .aggregate(shared, scripts)
  .settings(settings, libraryDependencies ++= commonDependencies)

lazy val shared = project
  .disablePlugins(ScalafmtPlugin)
  .disablePlugins(ScalastylePlugin)
  .settings(settings, libraryDependencies ++= commonDependencies)

lazy val scripts = project
  .disablePlugins(ScalafmtPlugin)
  .disablePlugins(ScalastylePlugin)
  .disablePlugins(sbtassembly.AssemblyPlugin)
  .settings(settings, libraryDependencies ++= commonDependencies)
  .dependsOn(shared % "compile->compile;test->test")

lazy val settings = Seq(
  assemblyJarName in assembly := s"$projectName-${name.value}-assembly-$version.jar",
  test in assembly := {},
  scalacOptions ++= Seq(),
  resolvers ++= Seq(
    Resolver.sonatypeRepo("releases"),
    "aws-glue-etl-artifacts" at "https://aws-glue-etl-artifacts.s3.amazonaws.com/release/"
  )
)

lazy val commonDependencies = Seq(
  "org.json4s" %% "json4s-jackson" % "4.1.0-M2",
  "org.yaml" % "snakeyaml" % "1.33",
  "org.scala-lang.modules" %% "scala-parser-combinators" % "2.1.1",
  "software.amazon.awssdk" % "s3" % "2.20.30",
  "software.amazon.awssdk" % "secretsmanager" % "2.20.30",
  "software.amazon.awssdk" % "ses" % "2.20.30",
  "com.amazonaws" % "AWSGlueETL" % "4.0.0" % Provided,
  "org.scalatest" %% "scalatest" % "3.0.8" % "test"
)

fork in ThisBuild := true
parallelExecution in ThisBuild := false
logBuffered in ThisBuild := false
testOptions in ThisBuild += Tests.Argument(TestFrameworks.ScalaTest, "-oD")

javaOptions ++= Seq(
  "-XX:+CMSClassUnloadingEnabled",
  "-XX:MaxMetaspaceSize=512M",
  "-XX:MetaspaceSize=256M",
  "-Xms512M",
  "-Xmx2G",
  "-XX:MaxPermSize=2048M"
)

project/build.properties

sbt.version = 1.8.2

project/plugins.sbt

addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.2.1")
addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "1.0.0")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.1.1")

1)エラー内容

$ sbt assembly

[error] 4 error(s) were encountered during the merge:
[error] java.lang.RuntimeException:
[error] Deduplicate found different file contents in the following:
[error]   Jar name = snowflake-jdbc-3.13.29.jar, jar org = net.snowflake, entry target = mozilla/public-suffix-list.txt
[error]   Jar name = httpclient-4.5.13.jar, jar org = org.apache.httpcomponents, entry target = mozilla/public-suffix-list.txt
・・・略・・・

3)原因

ライブラリの依存関連部分(commonDependencies部分)で
各ライブラリの更に依存しているライブラリで重複が発生したため 

4)解決案

sbt-assembly での同じファイル名のマージ方法として
assemblyMergeStrategy が用意されているので、
「build.sbt」に組み込む。
なお、組み込み方は以下「修正版 build.sbt の一部」を参照のこと

ただし、以下のサイト

https://stackoverflow.com/questions/25144484/sbt-assembly-deduplication-found-error

にある
~~~~~~
assemblyMergeStrategy in assembly := {
 case PathList("META-INF", _*) => MergeStrategy.discard
 case _                        => MergeStrategy.first
}
~~~~~~
をそのまま組み込むと、別のエラーがでたので、
組み込み方には工夫(Try&Error?)が必要かと、、、

また、警告が発生するが、、、今は無視、、、

修正版 build.sbt の一部

lazy val settings = Seq(
  assemblyJarName in assembly := s"$projectName-${name.value}-assembly-$version.jar",
  test in assembly := {},
  // ★ここを追加
  assemblyMergeStrategy in assembly := {
    case PathList("META-INF", "MANIFAST.MF") => MergeStrategy.discard
    case _                        => MergeStrategy.first
  },
  scalacOptions ++= Seq(),
  resolvers ++= Seq(
    Resolver.sonatypeRepo("releases"),
    "aws-glue-etl-artifacts" at "https://aws-glue-etl-artifacts.s3.amazonaws.com/release/"
  )
)

5)補足:sbt-assembly での同じファイル名のマージ方法

* 以下を参考に行うといいかも、、、

https://github.com/sbt/sbt-assembly#merge-strategy

* 以下にある書き方も参考になる

https://qiita.com/TakashiOshikawa/items/2a9f4f7a0c88e9629413

// より抜粋

assemblyMergeStrategy in assembly := {
  case PathList(ps @ _*) if ps.last endsWith ".html" => MergeStrategy.first
  case PathList("org", "slf4j", xs @ _*)             => MergeStrategy.first
  case PathList(ps @ _*) if ps.last endsWith ".properties" => MergeStrategy.first
  // 略
  case PathList(ps @ _*) if ps.last endsWith ".txt" => MergeStrategy.first
  case "application.conf"                            => MergeStrategy.concat
  case "unwanted.txt"                                => MergeStrategy.discard
  case "BUILD"                                       => MergeStrategy.discard
  case PathList("META-INF", xs @ _*)                 => MergeStrategy.discard
  case x =>
    val oldStrategy = (assemblyMergeStrategy in assembly).value
    oldStrategy(x)
}

その他日本語で読める参考文献
https://www.sassy-blog.com/entry/20171220/1513777494
https://qiita.com/TakashiOshikawa/items/2a9f4f7a0c88e9629413
https://qiita.com/ytayta/items/bdaa3d28f91bf3283184
https://tullio.hatenablog.com/

Value Explanation
MergeStrategy.deduplicate 既定値
MergeStrategy.first クラスパスの順序で最初に一致するファイルを選択
MergeStrategy.last クラスパスの順序で最後に一致するファイルを選択
MergeStrategy.singleOrError 衝突したらエラーを発生させる
MergeStrategy.concat ファイルを連結
MergeStrategy.filterDistinctLines 連結するが、重複は除外
MergeStrategy.rename jarファイル名を変更
MergeStrategy.discard 一致するファイルを破棄
MergeStrategy.preferProject 最初のプロジェクトファイルを選択

【2】警告「re-run with -deprecation for details」が表示

* 以下に素晴らしい記事が、、、

https://qiita.com/nyango/items/831392ef7429e0e784fb

1)警告内容

[warn] there was one deprecation warning; re-run with -deprecation for details
[warn] there was one feature warning; re-run with -feature for detail

2)対応策

* 「scalacOptions ++= Seq("-deprecation", "-feature")」を追加

修正版 build.sbt の一部

lazy val settings = Seq(
  assemblyJarName in assembly := s"$projectName-${name.value}-assembly-$version.jar",
  test in assembly := {},
  // ★ここを修正
  scalacOptions ++= Seq("-deprecation", "-feature"),
  assemblyMergeStrategy in assembly := {
    case PathList("META-INF", "MANIFAST.MF") => MergeStrategy.discard
    case _                        => MergeStrategy.first
  },
  resolvers ++= Seq(
    Resolver.sonatypeRepo("releases"),
    "aws-glue-etl-artifacts" at "https://aws-glue-etl-artifacts.s3.amazonaws.com/release/"
  )
)

3)補足:「sbt dependencyTree」について

* 使用しているライブラリの依存関係も含めて、
 ツリー状で表示できる
 => これで、重複しているライブラリをある程度、把握できる

コマンド例

sbt dependencyTree > out.txt

【3】警告「in is deprecated; migrate to slash syntax」が発生

1)警告内容

warning: method in in trait ScopingSetting is deprecated (since 1.5.0): 
`in` is deprecated; migrate to slash syntax
 - https://www.scala-sbt.org/1.x/docs/Migrating-from-sbt-013x.html#slash
  assemblyJarName in assembly := s"$projectName-${name.value}-assembly-$version.jar"

2)原因

SBT v1.5.0から「in」は非推奨

3)対応案

* 「in」の代わりに「/」を使う
(「`in` is deprecated; migrate to slash syntax」って言ってるし)

https://www.scala-sbt.org/1.x/docs/Migrating-from-sbt-013x.html#Migrating+to+slash+syntax
修正前

assemblyJarName in assembly := s"$projectName-${name.value}-assembly-$version.jar",

修正後

assembly / assemblyJarName := s"$projectName-${name.value}-assembly-$version.jar",

【4】警告「method sonatypeRepo in class ResolverFunctions is deprecated」が発生

1)警告内容

warning: method sonatypeRepo in class ResolverFunctions is deprecated (since 1.7.0):
 Use sonatypeOssRepos instead e.g. `resolvers ++= Resolver.sonatypeOssRepos("snapshots")`
    Resolver.sonatypeRepo("releases"),

2)原因

SBT v1.7.0から「sonatypeRepo」は非推奨

3)対応案

修正後

  resolvers ++= Seq(
    Resolver.sonatypeRepo("releases"),
    "aws-glue-etl-artifacts" at "https://aws-glue-etl-artifacts.s3.amazonaws.com/release/"
  )

修正後

  // もっときれいに書けると思うが、、、
  // (戻り値がSeqに変わっているのでそのまま置き換えは不可)
  resolvers ++= (
    Resolver.sonatypeOssRepos("releases") ++
    Seq(
      "aws-glue-etl-artifacts" at "https://aws-glue-etl-artifacts.s3.amazonaws.com/release/"
    )
  )

関連記事

SBT ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2023/03/22/000000
SBT ~ 基本編 / build.sbt ~
https://dk521123.hatenablog.com/entry/2023/01/27/000000
SBT ~ 基本編 / sbtコマンド ~
https://dk521123.hatenablog.com/entry/2023/01/26/000000
SBT ~ sbtプラグイン
https://dk521123.hatenablog.com/entry/2023/01/25/000000
SBT ~ JAR作成/実行 ~
https://dk521123.hatenablog.com/entry/2023/10/12/200450
Scala ~ 環境構築編 ~
https://dk521123.hatenablog.com/entry/2023/03/10/193805
Scala ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2023/03/12/184331