Over a million developers have joined DZone.

Full-fat SBT Projects

· Java Zone

What every Java engineer should know about microservices: Reactive Microservices Architecture.  Brought to you in partnership with Lightbend.

Akka Extras use the full .scala SBT syntax. This is different from the .sbt syntax, so let us explore how to construct the Scala syntax build, including publishing to Sonatype. We will explore this on the real EigengoBuild object.

The build object

The EigengoBuild extends the Build object, which is the project settings. In this file, we will define the modules as well as the root module, which aggregates the child modules. Let’s explore the overall stucture.

object EigengoBuild extends Build {
  // contains the modules and build settings

object Publish {
  // contains settings for publishing

object Dependencies {
  // contains dependencies

Let’s explore the EigengoBuild‘s main structure. We begin with the settings and the modules. Thesettings and defaultSettings hold the global and module-specific SBT settings. We then refer and use these settings sequences.

The override val settings holds the global settings for the project. We set the organisation,version and scalaVersion SBT settings. The defaultSettings holds the settings that will be used in each module. These include the compiler options (scalac and javac), the threading behaviour and the artefact resolvers. If you have a local/enterprise repository, you will need to add it to theresolverssequence. Notice that some of the keys in the settings are pulled from our Publish object as well as objects that the plugins define. (Ex gratia graphSettings, defined innet.virtualvoid.sbt.graph.Plugin.)

object EigengoBuild extends Build {

  override val settings = super.settings ++ Seq(
    organization := "org.eigengo.akka-extras",
    version := "0.1.0",
    scalaVersion := "2.10.1"

  lazy val defaultSettings = 
    Defaults.defaultSettings ++ 
    Publish.settings ++ 
    graphSettings ++ 
      scalacOptions in Compile ++= Seq("-encoding", "UTF-8", 
      javacOptions in Compile ++= Seq("-source", "1.6", 
                                      "-target", "1.6", 
    // https://github.com/sbt/sbt/issues/702
    javaOptions += "-Djava.util.logging.config.file=logging.properties",
    javaOptions += "-Xmx2G",
    outputStrategy := Some(StdoutOutput),
    fork := true,
    maxErrors := 1,
    resolvers ++= Seq(
      "Spray Releases" at "http://repo.spray.io",
    parallelExecution in Test := false
  ) ++ ScctPlugin.instrumentSettings // ++ ScalastylePlugin.Settings


Now that we have the settings, we can define the modules and pull in the settings we have defined above. Here, we have all the modules that make up Akka Extras. We use underscore for the variable name and dash for the directory name. So, the apple_push variable defines a module that lives in the apple-pushdirectory.

The modules include settings, which usually define the libraryDependencies. The variables that hold the depndencies themselves are defined further down, in the Dependencies object. (Hence the import Dependencies._ above.) Under each directory, we have the usual Maven-esque structuresrc/main/scala,
src/main/resourcessrc/test/scala and so on.

object EigengoBuild extends Build {

  override val settings = ...

  lazy val defaultSettings = Defaults.defaultSettings ++ 
                             Publish.settings ++ 
                             graphSettings ++ ...

  def module(dir: String) = 
    Project(id = dir, base = file(dir), settings = defaultSettings)

  import Dependencies._

  lazy val apple_push = module("apple-push") settings(
    libraryDependencies += akka,
    libraryDependencies += specs2 % "test"

  lazy val freemarker_templating = module("freemarker-templating") settings (
    libraryDependencies += freemarker,
    libraryDependencies += specs2 % "test"

  lazy val javamail = module("javamail") settings (
    libraryDependencies += mail,
    libraryDependencies += scalaz_core,
    libraryDependencies += typesafe_config,
    libraryDependencies += akka,
    libraryDependencies += specs2 % "test",
    libraryDependencies += dumbster % "test",
    libraryDependencies += akka_testkit % "test",

    publishArtifact in Compile := true

  lazy val main = module("main") 
    dependsOn(apple_push, freemarker_templating, javamail)

We are nearly at the end. The last thing we need to do is to aggregate all these projects into the rootproject. It does not have any further libraryDependencies, but it includes all other modules.

object EigengoBuild extends Build {

  lazy val root = Project(
    id = "parent", 
    base = file("."), 
    settings = defaultSettings ++ 
               ScctPlugin.mergeReportSettings ++ 
               Seq(publishArtifact in Compile := false),
    aggregate = Seq(apple_push, freemarker_templating, javamail) 


In the full-blown Scala builds, we define the individual dependencies as variables; it makes sense to separate them out to their own object. And that’s exactly what we’ve done in the Dependencies object

object Dependencies {
  val akka_version    = "2.1.2"

  val akka            = "com.typesafe.akka" %% "akka-actor"   % akka_version
  val scalaz_core     = "org.scalaz"        %% "scalaz-core"  % "7.0.0"
  val typesafe_config = "com.typesafe"       % "config"       % "1.0.0"
  val akka_testkit    = "com.typesafe.akka" %% "akka-testkit" % akka_version
  val specs2          = "org.specs2"        %% "specs2"       % "1.14"
  val mail            = "javax.mail"         % "mail"         % "1.4.2"
  val freemarker      = "org.freemarker"     % "freemarker"   % "2.3.19"
  val dumbster        = "dumbster"           % "dumbster"     % "1.6"

Publishing and the Publish object

We are publishing our artefacts to Sonatype OSS hosting; and we are using the sbt-release plugin. The plugin needs some settings that we define in the Publish object. The code follows the Publishing guide, but uses the full-blown .scala syntax instead of the .sbt syntax.

We define the settings variable: the sequence of SBT settings that is the Scala-syntax equivalent of writing

pomExtra  := ...
publishTo := ...

and others in the .sbt syntax. To keep things readable, we have pulled out the actual values likeakkaExtrasPomExtra, which is a proper variable in the Publish object; and we refer to it when we construct the SBT settings in this sequence. (Viz pomExtra := akkaExtrasPomExtra.)

The akkaExtrasCredentials is loaded from the ~/.sonatype file. (You don’t want to publish your credentials to GitHub–remember the sorry episode with people pushing their keyphrase-less private keys?)

This file must contain the realmhostusername and password property-like lines.

realm=Sonatype Nexus Repository Manager

So, onwards to the Publish object.

object Publish {

  lazy val settings = Seq(
    crossPaths := false,
    pomExtra := akkaExtrasPomExtra,
    publishTo < <= version { v: String =>
      val nexus = "https://oss.sonatype.org/"
      if (v.trim.endsWith("SNAPSHOT")) 
        Some("snapshots" at nexus + "content/repositories/snapshots")
        Some("releases" at nexus + "service/local/staging/deploy/maven2")
    credentials ++= akkaExtrasCredentials,
    organizationName := "Eigengo",
    organizationHomepage := Some(url("http://www.eigengo.com")),
    publishMavenStyle := true,
    // Maven central cannot allow other repos.  
    // TODO - Make sure all artifacts are on central.
    pomIncludeRepository := { x => false }

  val akkaExtrasPomExtra = (

  val akkaExtrasCredentials = Seq(Credentials(Path.userHome / ".sonatype"))



This completes the post about how we build the multi-module Akka Extras project. I hope you will find it useful for your own projects. The source code is at https://github.com/eigengo/akka-extras.

Microservices for Java, explained. Revitalize your legacy systems (and your career) with Reactive Microservices Architecture, a free O'Reilly book. Brought to you in partnership with Lightbend.


Published at DZone with permission of Jan Machacek, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}