読者です 読者をやめる 読者になる 読者になる

scala sbtプラグインのproguardでつくったjarでClassNotFoundException

scalaを悩みつつ書いてsbtからproguardして実行可能jarを作成しました。
テストしてみるとorg.apache.commons.logging.impl.LogFactoryImplで
"ClassNotFoundException"が発生しました。。
対処法の備忘録。



原因はproguardが必要なclassファイルを不要と判断して
jarに含めてくれなかったことですね。
proguardを直に使っている場合は
"-keep"を使って含めるclassなどを指定してやればいいのですが、
今はsbtからproguardを使っているのでやり方を調べました。


結局Project定義のscalaファイルに下記のように指定してやればいいようです。

MyProject.scala

import sbt._

class MyProject(info: ProjectInfo) extends DefaultProject(info) with ProguardProject {

  override def mainClass = Some("zz.yy.xxx.Main")
  override def proguardOptions = List("-keepclasseswithmembers public class * " + "{ public static void main(java.lang.String[]); }",
                                      proguardKeepLimitedSerializability,
                                      proguardKeepAllScala,
                                      "-keep interface scala.ScalaObject",
                                      "-keep public class org.apache.commons.logging.impl.LogFactoryImpl",
                                      "-keep public class org.apache.commons.logging.impl.Jdk14Logger { *** <init>(...); }")
  override def proguardInJars = Path.fromFile(scalaLibraryJar) +++ super.proguardInJars
  
}


ポイントは"override def proguardOptions"です。
List[String]の形でオプションをproguardに渡せるので、
今回であれば

"-keep public class org.apache.commons.logging.impl.LogFactoryImpl"
"-keep public class org.apache.commons.logging.impl.Jdk14Logger { *** <init>(...); }"

を追加しています。


追加後には

> reload
> proguard

とすれば指定したclassを含んだ実行可能jarが出来上がっているはずです。
reloadを忘れて少し悩みました。。