Akka HTTP ambiguous implicit conversion - scala

I'm cutting my teeth on Akka HTTP by working this example. For the purposes of learning, I converted it to a Maven project. However, I'm getting compilation errors as follows using Akka v2.3.12 and Akka Stream v1.0. The POST DSL fails with similar errors that I'm not posting for brevity. How can I get the example to run?
pathPrefix("ip") {
(get & path(Segment)) { ip =>
complete {
fetchIpInfo(ip).map[ToResponseMarshallable] {
case Right(ipInfo) => ipInfo
case Left(errorMessage) => BadRequest -> errorMessage
}
}
}
[ERROR] found : akka.http.scaladsl.server.Directive[(String,)]
[ERROR] required: ?{def apply: ?}
[ERROR] Note that implicit conversions are not applicable because they are ambiguous:
[ERROR] both method addDirectiveApply in object Directive of type [L](directive: akka.http.scaladsl.server.Directive[L])(implicit hac: akka.http.scaladsl.server.util.ApplyConverter[L])hac.In => akka.http.scaladsl.server.Route
[ERROR] and method fromDirective in object ConjunctionMagnet of type [L, R](other: akka.http.scaladsl.server.Directive[R])(implicit join: akka.http.scaladsl.server.util.TupleOps.Join[L,R])akka.http.scaladsl.server.ConjunctionMagnet[L]{type Out = akka.http.scaladsl.server.Directive[join.Out]}
[ERROR] are possible conversion functions from akka.http.scaladsl.server.Directive[(String,)] to ?{def apply: ?}
[ERROR] (get & path(Segment)) { ip =>
error: akka.http.scaladsl.server.Directive[(String,)] does not take parameters
[ERROR] (get & path(Segment)) { ip =>

Turns out this is due to the deep implicit chain that Spray (and hence akka-http) uses so getting the imports right is crucial. Very few examples show the imports and those that do, use old libraries.

Related

Convert Scala ListBuffer to JSON via Case Class using Play JSON API

I have a case class defined as case class IndexList(value: ListBuffer[String])
I'm unable to convert this to JSON using Play API.
I've tried
object IndexList{
implicit val indexListWrites = Json.writes[IndexList]
}
as part of Macro Inception but it fails giving compilation error:
exception during macro expansion:
[error] java.lang.NoSuchMethodError: scala.collection.immutable.$colon$colon.tl$1()Lscala/collection/immutable/List;
I've also tried
object IndexList{
implicit val indexListWrites: Writes[IndexList] = Writes{
(indexList: IndexList) => JsArray(indexList.value)
}
}
but fails with error:
type mismatch;
[error] found : scala.collection.mutable.ListBuffer[String]
[error] required: Seq[play.api.libs.json.JsValue]
Any help regarding either of the methods would be helpful.
If there are other ways to accomplish this, it's fine as well.

Slick 3.1.1 ambiguous implicit values involving filter and implicit CanBeQueryCondition

I have been trying to create a Generic Dao over Slick 3.1.1 and it includes a generic filter that competes with JPA's findByExample, see the following files:
GenericDaoImpl.scala Generic level reusable across all Models
UserDao.scala Generic plus customizations for the User model
UserService.scala Wraps the UserDao into more services level functionality
In this last file I try to use the generic filter function to find a user by its registered email, like this:
// this will implicitly exec and wait indefinitely for the
// db.run Future to complete
import dao.ExecHelper._
def findByEmail(email: String): Option[UserRow] = {
userDao.filter(_.email === email).headOption
}
but this produces the compiler error:
[error] /home/bravegag/code/play-authenticate-usage-scala/app/services/UserService.scala:35: value === is not a member of String
[error] userDao.filter(email === _.email).headOption
[error] ^
[error] /home/bravegag/code/play-authenticate-usage-scala/app/services/UserService.scala:35: ambiguous implicit values:
[error] both value BooleanOptionColumnCanBeQueryCondition in object CanBeQueryCondition of type => slick.lifted.CanBeQueryCondition[slick.lifted.Rep[Option[Boolean]]]
[error] and value BooleanCanBeQueryCondition in object CanBeQueryCondition of type => slick.lifted.CanBeQueryCondition[Boolean]
[error] match expected type slick.lifted.CanBeQueryCondition[Nothing]
[error] userDao.filter(email === _.email).headOption
[error] ^
Can anyone advice on how the implicit declaration of the filter function below can be improved to solve this compiler error?
The implementation of the filter function (found in GenericDaoImpl.scala) is:
// T is defined above as T <: Table[E] with IdentifyableTable[PK]
override def filter[C <: Rep[_]](expr: T => C)
(implicit wt: CanBeQueryCondition[C]) : Future[Seq[E]] =
db.run(tableQuery.filter(expr).result)
As far as I can see you are simply lacking you profile API import in UserService.
Just add there this import: import profile.api._ and it should work.
EDIT: BTW I see many people building their own version of base CRUDs for Slick. Did you try some existing thin libraries doing just that e.g. here: https://github.com/VirtusLab/unicorn ? It's not really related to this question but it may be worth to take a look.

Implementing custom foreach in order to better understand types and function composition

In order to try and understand Scala's type system I'm attempting
to implment a custom implementation for List.foreach method :
package com
object customForEach extends App {
class customForEach[B, A] extends Iterable[A] with collection.Seq[A] {
def foreach[B](f: A ⇒ B) {
var these = this
while (!these.isEmpty) {
f(these.head)
these = these.tail
}
}
def tail = this match {
case h :: t ⇒ t
}
}
}
When I complile this code I receive errors :
[error] \Desktop\Scala\src\main\scala\typeparam.scala:16: constructor cannot be instantiated to expected type;
[error] found : scala.collection.immutable.::[B(in class ::)]
[error] required: com.customForEach.customForEach[B(in class customForEach),A]
[error] case h :: t ? t
[error] ^
[error] \Desktop\Scala\src\main\scala\typeparam.scala:16: not found: value t
[error] case h :: t ? t
[error] ^
[error] \Desktop\Scala\src\main\scala\typeparam.scala:11: type mismatch;
[error] found : Seq[A]
[error] required: com.customForEach.customForEach[B,A]
[error] these = these.tail
[error] ^
[error] three errors found
[error] (compile:compile) Compilation failed
[error] Total time: 0 s, completed 31-Jan-2015 11:53:40
In particular I find it iteresting how println can be composed with List in this fashion : List(1,2,3).foreach(println)
Do I need to add extend another trait in order to access the .tail function ?
For this error :
not found: value t
[error] case h :: t ? t
Shouldn't t be found since it is created using pattern match operator :: ?
There are many reasons why this code won't work. In order to understand the first compiler error not found: value t, you must look at the error immediately before it. :: exists solely for List, but here you do not have a List, only Iterable with Seq. That pattern match can't work, which causes t to become "not found".
There are even larger problems than that, though. Even if you remove your definition of tail (which is unnecessary), you'll then find that you're missing abstract method definitions for apply, iterator, and length from the Seq trait. I imagine you're doing this because you can't extend List, which is sealed. You can copy the implementations of apply, and length from LinearSeqOptimized, then easily implement an iterator method, but there's still another problem: your class does not have a constructor.
Okay, well we'll look at what List does again. List is abstract and has two sub-types, :: and Nil. Nil is just a case object, and :: has a constructor that accepts the head and tail of the List. This isn't going to help you very much, unless you also want to duplicate the code for :: and Nil as well.
Scala collections are very large complicated beasts, and extending them to override one method is not a simple process.

Ambiguous implicit conversions causing compile failure in Scalatest and Argonaut.io

I'm currently doing that most noble of programming endeavors, writing tests for Json encoding / decoding. I'm using Argonaut.io for Json and Scalatest for my testing framework. Under scalatest, the use of === during assertion verification provides additional information if a failure occurs, while the use of ==simply gives this org.scalatest.exceptions.TestFailedException was thrown.. However, the scala compiler is not happy. Here's the code:
val default = new Broadcast("default", "default", "default")
test("Should parse out network when present") {
val hcursor = testHCursor(jsonPath + "complete-broadcast.json")
val actualNetwork = Parser.BroadcastDecodeJson(hcursor)
.getOr(default)
.network
assert(actualNetwork === "ESPNU")
}
That spews out this:
[info] Compiling 1 Scala source to /home/vagrant/waltercamp/waltercamp-dataservice/target/scala-2.10/test-classes...
[error] /home/vagrant/waltercamp/waltercamp-dataservice/src/test/scala/io/ptx/waltercamp/schedules/BroadcastParserSuite.scala:16: type mismatch;
[error] found : actualNetwork.type (with underlying type String)
[error] required: ?{def ===(x$1: ? >: String("ESPNU")): ?}
[error] Note that implicit conversions are not applicable because they are ambiguous:
[error] both method ToEqualOps in trait ToEqualOps of type [F](v: F)(implicit F0: scalaz.Equal[F])scalaz.syntax.EqualOps[F]
[error] and method convertToEqualizer in trait Assertions of type (left: Any)BroadcastParserSuite.this.Equalizer
[error] are possible conversion functions from actualNetwork.type to ?{def ===(x$1: ? >: String("ESPNU")): ?}
[error] assert(actualNetwork === "ESPNU")
[error] ^
[error] one error found
[error] (test:compile) Compilation failed
The use == however provides a clean compilation and pass. Is there a way provide the compiler a hint as to which conversion, or the conversion order, to use?
I'd go with ScalaTest's version here. One approach would be to apply the conversion explicitly:
assert(convertToEqualizer(actualNetwork) === "ESPNU")
That's kind of unpleasant, though, and involves a lot of repetitious boilerplate if you're using === many times in a file. Another way would be to exclude the Scalaz conversion from the general import:
import scalaz._, Scalaz.{ ToEqualOps => _, _ }
You could also switch to à la carte imports for Scalaz and just be sure you don't pull in ToEqualOps via scala.syntax.equal._. I'll admit I find à la carte imports a pain to maintain sometimes, but if you're not doing much with Scalaz in the test this wouldn't be too bad.

slick 2.0 define generic `find by field` method

import scala.slick.driver.MySQLDriver.simple._
class RichTable[T](tag: Tag, name: String) extends Table[T](tag, name) {
case class QueryExt[B](q: Query[RichTable.this.type, B]) {
def whereEq[C](col: RichTable.this.type => Column[C], c: C) = {
q.filter { fields =>
col(fields) === c
}
}
}
}
Then it complains
[error] /home/jilen/workspace/play-slick/src/main/scala/play/slick/SlickQueryExtension.scala:10: value === is not a member of slick.driver.MySQLDriver.simple.Column[C]
[error] col(fields) === c
[error] ^
[error] /home/jilen/workspace/play-slick/src/main/scala/play/slick/SlickQueryExtension.scala:9: ambiguous implicit values:
[error] both value BooleanColumnCanBeQueryCondition in object CanBeQueryCondition of type => scala.slick.lifted.CanBeQueryCondition[scala.slick.lifted.Column[Boolean]]
[error] and value BooleanOptionColumnCanBeQueryCondition in object CanBeQueryCondition of type => scala.slick.lifted.CanBeQueryCondition[scala.slick.lifted.Column[Option[Boolean]]]
[error] match expected type scala.slick.lifted.CanBeQueryCondition[Nothing]
[error] q.filter { fields =>
[error] ^
[error] two errors found
[error] (compile:compile) Compilation failed
[error] Total time: 0 s, completed Mar 6, 2014 1:21:48 AM
There have been questions about this, but the answers did not work for 2.0
How to parametrize Scala Slick queries by WHERE clause conditions?
Slick doesn't have any information about C, so it doesn't know if it can and how it should map it to a database value and if it can use === on it. So you get a type error. You will have to use Scala's type system to restrict the type to one for which Slick knows how to map it. You can do this by providing a so-called Context Bound, in this case :BaseColumnType.
def whereEq[C:BaseColumnType](col: RichTable.this.type => Column[C], c: C) = {
q.filter { fields =>
col(fields) === c
}
}
BaseColumnType is provided by Slick and using it in this way basically tells the Scala compiler to look for an implicit value of type BaseColumnType[C] in scope, where you call whereEq. Because then it is usually known what C will actually be. Slick comes with BaseColumnType[Int], BaseColumnType[String], etc. so at the call site, the Scala compiler can find one when your C is really an Int or String in that particular call and this way pass the info further to Slick.
Same for LiuTiger's question. abstract class Crud[..., PK:BaseColumnType] should do the trick, a trait doesn't work with context bounds. When implementing an abstract DAO be prepared to face a lot of challenges and get to the edges of your Scala type system skills and learn quite a bit about type inference order, implicit parameters, etc.