0

I have the following piece of code that fails compilation for some strange reason!

def createNewPowerPlant = Action.async(parse.tolerantJson) { request =>
    request.body.validate[PowerPlantConfig].fold(
      errors => {
        Future.successful(
          BadRequest(Json.obj("message" -> s"invalid PowerPlantConfig $errors"))
        )
      },
      success => { // fails here!!
        dbService.newPowerPlant(toPowerPlantRow(success)).recover {
          case NonFatal(ex) =>
            Future.successful { UnprocessableEntity(
              Json.obj("message" -> s"Could not create new PowerPlant because of ${ex.getMessage}")
            ) }
        }
        Future.successful { Ok("") }
      }
    )
  }

And this is what I see as the reason:

Controller.scala:103: a type was inferred to be `Any`; this may indicate a programming error.
[error]       success => {
[error]                  ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 16 s, completed Aug 21, 2017 9:46:30 AM

Any ideas as to why this error happens? I'm sure it has got something to do with the compiler as I have similar code in my controller which compiles!

3
  • If I remove the recover code blcok, I can get past the compiler! Why is this? Commented Aug 21, 2017 at 9:07
  • Have you tried to replace the curly braces { } with parentheses () immediately after case NonFatal(ex) => Future.successful ? Commented Aug 21, 2017 at 10:39
  • Yes, I did! But that is not the problem! There is something fundamentally wrong with the way the compile sees this bit of code! Commented Aug 21, 2017 at 10:57

2 Answers 2

1

You have "-Xfatal-warnings" in the build.sbt. That makes the compiler to throw a compilation error where in the regular case it would be just a warning. To check this I've commented the "-Xfatal-warnings". Then sbt clean compile gives this:

alex@POSITRON /ssd2/projects/PowerPlantProblem/plant-simulator $ sbt clean compile
[info] Loading project definition from /ssd2/projects/PowerPlantProblem/plant-simulator/project
[info] Updating {file:/ssd2/projects/PowerPlantProblem/plant-simulator/project/}plant-simulator-build...
Waiting for lock on /home/alex/.ivy2/.sbt.ivy.lock to be available...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Set current project to plant-simulator (in build file:/ssd2/projects/PowerPlantProblem/plant-simulator/)
[success] Total time: 0 s, completed Aug 21, 2017 3:39:57 PM
[info] Updating {file:/ssd2/projects/PowerPlantProblem/plant-simulator/}root...
[info] Resolving jline#jline;2.14.3 ...
[info] Done updating.
[info] Compiling 31 Scala sources and 2 Java sources to /ssd2/projects/PowerPlantProblem/plant-simulator/target/scala-2.11/classes...
[warn] /ssd2/projects/PowerPlantProblem/plant-simulator/app/com/inland24/plantsim/controllers/PowerPlantController.scala:102: a type was inferred to be `Any`; this may indicate a programming error.
[warn]           case Some(row) => dbService.newPowerPlant(row) recoverWith{
[warn]                ^
[warn] one warning found
[success] Total time: 23 s, completed Aug 21, 2017 3:40:20 PM
alex@POSITRON /ssd2/projects/PowerPlantProblem/plant-simulator $ 

This means that my suggestion is true. So you either disable that "-Xfatal-warnings" or make the code to satisfy more strict requirements it brings on.

Now in order to understand that warning itself, take a look at the signature of recoverWith method:

def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U]

In your case T is Int. So any common ancestor of Int and Future[Result] is Any of course. You can make this compilable with "-Xfatal-warnings" just by inserting an Int value like here:

case Some(row) => dbService.newPowerPlant(row) recoverWith{
  case ex: Exception => Future.successful{
    UnprocessableEntity(
      Json.obj("message" -> s"Could not create new PowerPlant because of ${ex.getMessage}")
    )
    5
  }
}

The warning makes a sense here because the code is not clean: you are trying to recover a problem with inserting a row to DB (e.g. DB server is down) by returning UnprocessableEntity HTTP status which really does not make any sense, taking into account that you override this intention after that by Future.successful { Ok("") }.

Hope this helps.

Sign up to request clarification or add additional context in comments.

9 Comments

You can find the entire source code here: github.com/joesan/plant-simulator
I suspect that the linters that I have in my build.sbt is causing this problem!
I've updated the answer. So, I have cloned the repository and it compiles well on my laptop. Hard to say then why you are getting compiler error. If you have locally the same build.sbt then really strange. I am running on Linux, having Java8.
Hmm.. this is very wierd!
Man, god )) you've commented that part of the code as I see now. Checking.
|
0

With the hint from Alexander Arendar

I did the following to solve this:

def createNewPowerPlant = Action.async(parse.tolerantJson) { request =>
    request.body.validate[PowerPlantConfig].fold(
      errors => {
        Future.successful(
          BadRequest(Json.obj("message" -> s"invalid PowerPlantConfig $errors"))
        )
      },
      success => {
        toPowerPlantRow(success) match {
          case None => Future.successful(
            BadRequest(Json.obj("message" -> s"invalid PowerPlantConfig ")) // TODO: fix errors
          )
          case Some(row) =>
            dbService.newPowerPlant(row).materialize.map {
              case Success(insertedRecordId) =>
                Ok("TODO: Send a Success JSON back with the id of the newly inserted record")
              case Failure(ex) =>
                UnprocessableEntity(
                  Json.obj("message" -> s"Could not create new PowerPlant because of ${ex.getMessage}")
                )
            }
        }
      }
    )
  }

Notice I'm using the materialize FutureExtensions method from the Monix library!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.