mirelon
mirelon

Reputation: 4996

SBT incorrect order of compilation

TL/DR: Checkout last two commits and run sbt clean compile: https://github.com/mirelon/akka-in-action/tree/json/chapter2

There is RestInterface.scala:

package com.goticks

import akka.actor._

import spray.routing._
import spray.http.StatusCodes
import spray.httpx.SprayJsonSupport._
import spray.routing.RequestContext
import akka.util.Timeout
import scala.concurrent.duration._
import scala.language.postfixOps

class RestInterface extends HttpServiceActor
                    with RestApi {
  def receive = runRoute(routes)
}

trait RestApi extends HttpService { actor: Actor =>
  import context.dispatcher
  import com.goticks.TicketProtocol._

  implicit val timeout = Timeout(10 seconds)
  import akka.pattern.ask

  def routes: Route =

    path("events") {
      get { requestContext =>
        context.actorOf(Props[Resu]).ask(GetEvents)
      }
    }

}

class Responder(requestContext:RequestContext) extends Actor {
  import TicketProtocol._

  def receive = {

    case Events(events) =>
      requestContext.complete(StatusCodes.OK, events)
      self ! PoisonPill

  }
}

and Resu.scala (note that Resu is alphabetically after RestInterface)

package com.goticks

import akka.actor.Actor

class Resu extends Actor {
  import TicketProtocol._
  import spray.json._

  def receive = {

    case GetEvents => {
      println(Event(event = "E").toJson)
    }
  }
}

object TicketProtocol {
  import spray.json._

  case class Event(event:String)

  case object GetEvents

  case class Events(events:List[Event])

  object Event extends DefaultJsonProtocol {
    implicit val format = jsonFormat1(Event.apply)
  }

}

build.sbt:

name := "goticks"

version := "0.1-SNAPSHOT"

organization := "com.goticks"

scalaVersion := "2.11.1"

libraryDependencies ++= {
  val akkaVersion = "2.3.4"
  val sprayVersion = "1.3.1"
  Seq(
    "com.typesafe.akka" %% "akka-actor" % akkaVersion,
    "io.spray" %% "spray-can" % sprayVersion,
    "io.spray" %% "spray-routing" % sprayVersion,
    "io.spray" %% "spray-json" % "1.2.6"
  )
}

build.properties;

sbt.version=0.13.7

plugins.sbt:

resolvers += Classpaths.typesafeResolver

resolvers += "sbt-idea" at "http://mpeltonen.github.com/maven/"

addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.6.0")

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.11.2")

addSbtPlugin("com.typesafe.sbt" % "sbt-start-script" % "0.10.0")

addSbtPlugin("com.typesafe.sbt" % "sbt-multi-jvm" % "0.3.8")

Compilation issue

When I run sbt clean compile, everything is ok. But when I refactor the Resu class into Ress (note that Ress is alphabetically before RestInterface) (also rename its file, the diff can be viewed here: https://github.com/mirelon/akka-in-action/commit/583ca801fb7d1564024eee2f98d57f03ecacc6e5), then there is a compilation error:

[error] /home/miso/IdeaProjects/akka-in-action/chapter2/src/main/scala/com/goticks/Ress.scala:12: Cannot find JsonWriter or JsonFormat type class for com.goticks.TicketProtocol.Event
[error]       println(Event(event = "E").toJson)
[error]                                  ^
[error] one error found
[error] (compile:compile) Compilation failed

Clearly there is an implicit json writer missing. Could it be due to incorrect order of compiling? Could sbt compile the classes in alphabetical order, ignoring imports?

Upvotes: 4

Views: 625

Answers (1)

jsuereth
jsuereth

Reputation: 5624

Yes, sbt always compiles in alphabetical order. The issue is sbt has no idea the dependencies between files until it runs the compiler.

What you're seeing is the scala compiler itself is dependent on the ordering of source files. Sbt always sorts source files so you can at least work around these issues by placing code in an ordering that works.

I'm not 100% sure why you're hitting such an issue from some implicits + macro hackery, but that could be wrong.

Upvotes: 2

Related Questions