scala-pickling in POJO in scala 2.11 - Is it really simple? - scala

I'm trying to use scala-pickling because at site github it seems so easy and clean. But, I'm failing in use it in this simple REPL:
scala> import scala.pickling._
import scala.pickling._
scala> import scala.pickling.Defaults._
import scala.pickling.Defaults._
scala> import binary._
import binary._
scala> class Xpto { var a = 0D; var b = 0 }
defined class Xpto
scala> val v = new Xpto { a = 1.23; b = 5 }
v: Xpto = $anon$1#636d2b03
scala> v.pickle
<console>:19: error: type mismatch;
found : v.type (with underlying type Xpto)
required: ?{def pickle: ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method PickleOps in package pickling of type [T](picklee: T)pickling.PickleOps[T]
and method pickleOps in trait Ops of type [T](picklee: T)scala.pickling.PickleOps[T]
are possible conversion functions from v.type to ?{def pickle: ?}
v.pickle
^
<console>:19: error: value pickle is not a member of Xpto
v.pickle
^
What is wrong?
I did access other issues on StackOverflow with this same type of question, for example:
Scala pickling: Simple custom pickler for my own class?
Obs.: I'm using this reference in build.sbt:
"org.scala-lang.modules" %% "scala-pickling" % "0.10.1"

Are you sure that those are the only imports you are using when in the REPL? The error above is, as it says:
Note that implicit conversions are not applicable because they are ambiguous:
both method PickleOps in package pickling of type [T](picklee: T)pickling.PickleOps[T]
and method pickleOps in trait Ops of type [T](picklee: T)scala.pickling.PickleOps[T]
are possible conversion functions from v.type to ?{def pickle: ?}
So you have at least two implicit conversions, from scala.pickling.PickleOps[T]() and scala.pickling.Ops.pickleOps. This is strange, because PickleOps is not an implicit class.
For me it works (Scala version 2.11.7 Java 1.7.0_79) in a fresh REPL:
scala> import scala.pickling._
scala> import scala.pickling.Defaults._
scala> import binary._
scala> class Xpto { var a = 0D; var b = 0 }
defined class Xpto
scala> val v = new Xpto { a = 1.23; b = 5 }
v: Xpto = cmd5$$anonfun$1$$anon$1#244da0ed
scala> v.pickle
res6: pickleFormat.PickleType = BinaryPickle([0,0,0,23,99,109,100,53,36,36,97,110,111,110,102,117,110,36,49,36,36,97,110,111,110,36,49,63,-13,-82,20,122,-31,71,-82,0,0,0,5])

Great! It runs!
I started a new fresh scala console.
I was using this reference to scala.pickling in build.sbt:
"org.scala-lang" %% "scala-pickling" % "0.10.1"
and now I'm using
"org.scala-lang.modules" %% "scala-pickling" % "0.10.1"
I'm also utilising Scala 2.11.6
Now it works perfectly, and really it's so simple.
scala> import scala.pickling._
import scala.pickling._
scala> import scala.pickling.binary._
import scala.pickling.binary._
scala> import scala.pickling.Defaults._
import scala.pickling.Defaults._
scala> class Xpto { var a = 0D; var b = 0; }
defined class Xpto
scala> val v = new Xpto { a = 1.23; b = 4; }
v: Xpto = $anon$1#1e7bd4df
scala> v.pickle
res0: pickling.binary.pickleFormat.PickleType = BinaryPickle([0,0,0,52,46,108,105,110,101,55,46,46,114,101,97,100,46,46,105,119,46,46,105,119,46,46,105,119,46,46,105,119,46,46,105,119,46,46,105,119,46,46,105,119,46,46,105,119,46,46,97,110,111,110,46,49,63,-13,-82,20,122,-31,71,-82,0,0,0,4])
I don't now if my others libraries references was generating that ambiguous refence. My references in build.sbt are:
libraryDependencies ++= Seq(
"log4j" % "log4j" % "1.2.17",
"javax.transaction" % "jta" % "1.1",
"com.typesafe.akka" %% "akka-actor" % "2.3.10",
"com.typesafe.akka" %% "akka-testkit" % "2.3.10",
"org.scalatest" %% "scalatest" % "3.0.0-SNAP4" % "test",
"org.apache.commons" % "commons-io" % "1.3.2",
"com.typesafe.akka" %% "akka-slf4j" % "2.3.11",
"ch.qos.logback" % "logback-classic" % "1.0.9",
"org.scala-lang.modules" %% "scala-pickling" % "0.10.1"
)
Thanks to Markus.

Related

Scala cats import for Id Monad Results in Compilation Failure

I do not understand how such a simple thing would be complicated? I'm trying to use the Id Monad from the typelevel cats library and for this purpose, I have added the following as my sbt dependency:
val scalaCATS = "org.typelevel" %% "cats-core" % "2.9.0"
val scalaCATSKernel = "org.typelevel" %% "cats-kernel" % "2.9.0"
val scalaCATSEffect = "org.typelevel" %% "cats-effect" % "3.4.2"
I then have defined the following in my object like this:
import cats._
import java.net.URL
import java.time.ZonedDateTime
case class LocationAPIObject[F[_]](
countryCode: F[String]
)
object Locations {
val api = LocationAPIObject[Id] //
......
......
}
[error] 40 | val api = LocationAPIObject[Id]
[error] | ^^
[error] | Not found: type Id
Any ideas as to what else I'm missing here?

How to convert JSON to scala shapeless.hlist?

I got json like {"name":"susan","age":25},and a hint to json keyset like "name:String,age:Int",how to create a HList from that json?
Based on the code you added and then deleted, it seems, having a runtime-string hint "name:String,age:Int" and runtime-string json {"name":"susan","age":25}, you want to get an HList with runtime reflection. You can do this as follows
import shapeless.HList
import scala.reflect.runtime
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
val tb = runtime.currentMirror.mkToolBox()
val jsonStr = """{"name":"susan","age":25}"""
val hint = "name:String,age:Int"
val classType = tb.define(tb.parse(s"case class Test($hint)").asInstanceOf[ImplDef]).asClass.toType
val hlist = tb.eval(q"""
import io.circe.generic.auto._
import io.circe.parser.decode
val classInstance = decode[$classType]($jsonStr)
import shapeless.Generic
Generic[$classType].to(classInstance.toOption.get)
""").asInstanceOf[HList]
println(hlist) // susan :: 25 :: HNil
Please notice that you do everything at runtime so you'll have no access to type String :: Int :: HNil at compile time and hlist has static type just HList (not String :: Int :: HNil) and HList is actually not better than just List[Any].
build.sbt
libraryDependencies ++= Seq(
scalaOrganization.value % "scala-reflect" % scalaVersion.value,
scalaOrganization.value % "scala-compiler" % scalaVersion.value,
"com.chuusai" %% "shapeless" % "2.4.0-M1",
"io.circe" %% "circe-core" % "0.13.0",
"io.circe" %% "circe-parser" % "0.13.0",
"io.circe" %% "circe-generic" % "0.13.0"
)
Actually, I guess we do someting strange. We use highly type-level libraries (shapeless, circe) aimed to static type safety and then run them at runtime with reflection ignoring type safety and getting actually List[Any] (HList).
I guess that if List[Any] (list of field values) is enough for you then you just need to use a more runtime library. For example, with json4s
import org.json4s.{JInt, JObject, JString, JValue}
import org.json4s.jackson.JsonMethods._
val jsonStr: String = """{"name":"susan","age":25}"""
val json: JValue = parse(jsonStr) //JObject(List((name,JString(susan)), (age,JInt(25))))
val l: List[JValue] = json.asInstanceOf[JObject].obj.map(_._2) //List(JString(susan), JInt(25))
val res: List[Any] = l.map {
case JString(s) => s
case JInt(n) => n
} //List(susan, 25)
build.sbt
libraryDependencies += "org.json4s" %% "json4s-jackson" % "3.6.9"
Actually the same can be done with Circe, just with parse instead of decode[A]
import io.circe.{Json, JsonNumber}
import io.circe.parser.parse
val jsonStr: String = """{"name":"susan","age":25}"""
val json: Json = parse(jsonStr).toOption.get //{"name":"susan","age":25}
val l: List[Json] = json.asObject.get.values.toList //List("susan", 25)
val res: List[Any] = l.map(_.fold[Any](null, null, (_: JsonNumber).toInt.get, identity[String], null, null)) //List(susan, 25)
If you need an instance of case class or a tuple rather than HList replace
tb.eval(q"""
import io.circe.generic.auto._
import io.circe.parser.decode
val classInstance = decode[$classType]($jsonStr)
import shapeless.Generic
Generic[$classType].to(classInstance.toOption.get)
""").asInstanceOf[HList] // susan :: 25 :: HNil
with
tb.eval(q"""
import io.circe.generic.auto._
import io.circe.parser.decode
decode[$classType]($json).toOption.get
""").asInstanceOf[Product] //Test(susan,25)
or
tb.eval(q"""
import io.circe.generic.auto._
import io.circe.parser.decode
val classInstance = decode[$classType]($json)
import shapeless.Generic
Generic[$classType].to(classInstance.toOption.get).tupled
""").asInstanceOf[Product] //(susan,25)
correspondingly.

Mocking a vararg tuple using mockito

I want to mock this method
def zadd[V: ByteStringSerializer](key: String, scoreMembers: (Double, V)*): Future[Long]
Tried this
mock.zadd(anyString(), Seq((anyDouble(), any String()), (anyDouble(), anyString())): _*)
doesnt work because mockito says 3 matchers expected, but got 5 instead.
so I try using How to properly match varargs in Mockito
but, I cant even use the code listed in that example
ArgumentMatchers.<String>any() gets flagged as error in my IDE saying not recognized type String
mockito-scala supports varargs out-of-the-box, for example
import cats.implicits._
import org.mockito.ArgumentMatchersSugar
import org.mockito.cats.IdiomaticMockitoCats
import org.mockito.scalatest.IdiomaticMockito
import org.scalatest._
import org.scalatest.concurrent.ScalaFutures
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
trait Foo {
def zadd(key: String, scoreMembers: (Double, String)*): Future[Long]
}
class HelloSpec extends FlatSpec
with Matchers
with IdiomaticMockito
with IdiomaticMockitoCats
with ScalaFutures
with ArgumentMatchersSugar {
"Foo" should "mock varargs" in {
val foo = mock[Foo]
foo.zadd("", *) returnsF 42L
foo.zadd("bar", (7.7, "qux")) returnsF 89L
foo.zadd("", (1.1, "")).futureValue should be (42L)
foo.zadd("bar", (7.7d, "qux")).futureValue should be (89L)
}
}
where
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest" % "3.0.8",
"org.mockito" %% "mockito-scala" % "1.5.13",
"org.mockito" %% "mockito-scala-scalatest" % "1.5.13",
"org.mockito" %% "mockito-scala-cats" % "1.5.13",
"org.typelevel" %% "cats-core" % "2.0.0-M4"
)

ambiguous implicit values: match expected type cats.derived.MkShow[A]: show cats:kittens

I'm trying to create Show Instance for my custom Config class.
The build.sbt file is -
name := "circe-demo"
version := "0.1"
scalaVersion := "2.11.12"
resolvers += Resolver.bintrayRepo("ovotech", "maven")
libraryDependencies += "io.circe" %% "circe-core" % "0.11.0"
libraryDependencies += "io.circe" %% "circe-parser" % "0.11.0"
libraryDependencies += "io.circe" %% "circe-generic" % "0.11.0"
libraryDependencies += "org.typelevel" %% "kittens" % "1.2.0"
libraryDependencies ++= Seq(
"is.cir" %% "ciris-cats",
"is.cir" %% "ciris-cats-effect",
"is.cir" %% "ciris-core",
"is.cir" %% "ciris-enumeratum",
"is.cir" %% "ciris-refined"
).map(_ % "0.12.1")
Complete code is -
import enumeratum.{Enum, EnumEntry}
sealed abstract class AppEnvironment extends EnumEntry
object AppEnvironment extends Enum[AppEnvironment] {
case object Local extends AppEnvironment
case object Testing extends AppEnvironment
case object Production extends AppEnvironment
override val values: Vector[AppEnvironment] =
findValues.toVector
}
import java.net.InetAddress
import scala.concurrent.duration.Duration
final case class ApiConfig(host: InetAddress, port: Int, apiKey: String, timeout: Duration)
import java.net.InetAddress
import cats.Show
import cats.derived.semi
import ciris.config.loader.AppEnvironment.{Local, Production, Testing}
import enumeratum.EnumEntry
import eu.timepit.refined.auto._
import eu.timepit.refined.types.string.NonEmptyString
import scala.concurrent.duration._
final case class Config(appName: NonEmptyString, environment: AppEnvironment, api: ApiConfig)
object Config {
implicit val showConfig: Show[Config] = {
implicit val showDuration: Show[Duration] =
Show.fromToString
implicit val showInetAddress: Show[InetAddress] =
Show.fromToString
implicit def showEnumEntry[E <: EnumEntry]: Show[E] =
Show.show(_.entryName)
// Show.show[Config](x => s"api = ${x.api} appName = ${x.appName} environment ${x.environment}")
semi.show
}
}
semi.show in the above code throws the below exception -
[error] /Users/rajkumar.natarajan/Documents/Coding/kafka_demo/circe-demo/src/main/scala/ciris/config/loader/Config.scala:32:5: ambiguous implicit values:
[error] both value emptyProductDerivedShow in trait MkShowDerivation of type => cats.derived.MkShow[shapeless.HNil]
[error] and method emptyCoproductDerivedShow in trait MkShowDerivation of type => cats.derived.MkShow[shapeless.CNil]
[error] match expected type cats.derived.MkShow[A]
[error] show
[error] ^
[error] one error found
[error] (Compile / compileIncremental) Compilation failed
[error]
I'm new to functional programming using cats.
How can I resolve this exception.
Unfortunately error reporting when such complicated implicits and macros are involved is far from perfect. The message you see actually means that some required implicits for the real generator (MkShow.genericDerivedShowProduct in this case) have not been found and the search went back to some where basic stuff where there is an ambiguity. And the stuff that is missing is mostly very basic such as an implicit for Show[Int] or Show[String]. The simplest way to get them all is to import cats.implicits._ but that will also bring catsStdShowForDuration which is a Show[Duration]. But since it's implementation is really the same as your custom one, it is easier to remove your custom one. One more thing that is missing is Show[NonEmptyString] and it is easy to create one
implicit def showNonEmptyString: Show[NonEmptyString] = Show.show(nes => nes)
To sum up, when I define your showConfig as
implicit val showConfig: Show[Config] = {
import cats.implicits._
// is already defined in cats.implicits._
//implicit val showDuration: Show[Duration] = Show.fromToString
implicit val showInetAddress: Show[InetAddress] = Show.fromToString
implicit def showEnumEntry[E <: EnumEntry]: Show[E] = Show.show(_.entryName)
implicit def showNonEmptyString: Show[NonEmptyString] = Show.show(nes => nes)
// Show.show[Config](x => s"api = ${x.api} appName = ${x.appName} environment ${x.environment}")
semi.show
}
it compiles for me.
P.S. is there any good reason why you put your AppEnvironment under ciris.* package? I'd say that generally putting your custom code into packages of 3-rd party library is an easy way to mess things up.

Circe Encoders and Decoders with Http4s

I am trying to use http4s, circe and http4s-circe.
Below I am trying to use the auto derivation feature of circe.
import org.http4s.client.blaze.SimpleHttp1Client
import org.http4s.Status.ResponseClass.Successful
import io.circe.syntax._
import org.http4s._
import org.http4s.headers._
import org.http4s.circe._
import scalaz.concurrent.Task
import io.circe._
final case class Login(username: String, password: String)
final case class Token(token: String)
object JsonHelpers {
import io.circe.generic.auto._
implicit val loginEntityEncoder : EntityEncoder[Login] = jsonEncoderOf[Login]
implicit val loginEntityDecoder : EntityDecoder[Login] = jsonOf[Login]
implicit val tokenEntityEncoder: EntityEncoder[Token] = jsonEncoderOf[Token]
implicit val tokenEntityDecoder : EntityDecoder[Token] = jsonOf[Token]
}
object Http4sTest2 extends App {
import JsonHelpers._
val url = "http://"
val uri = Uri.fromString(url).valueOr(throw _)
val list = List[Header](`Content-Type`(MediaType.`application/json`), `Accept`(MediaType.`application/json`))
val request = Request(uri = uri, method = Method.POST)
.withBody(Login("foo", "bar").asJson)
.map{r => r.replaceAllHeaders(list :_*)}.run
val client = SimpleHttp1Client()
val result = client.fetch[Option[Token]](request){
case Successful(response) => response.as[Token].map(Some(_))
case _ => Task(Option.empty[Token])
}.run
println(result)
}
I get multiple instances of these two compiler errors
Error:scalac: missing or invalid dependency detected while loading class file 'GenericInstances.class'.
Could not access type Secondary in object io.circe.Encoder,
because it (or its dependencies) are missing. Check your build definition for
missing or conflicting dependencies. (Re-run with `-Ylog-classpath` to see the problematic classpath.)
A full rebuild may help if 'GenericInstances.class' was compiled against an incompatible version of io.circe.Encoder.
Error:(25, 74) could not find implicit value for parameter encoder: io.circe.Encoder[Login]
implicit val loginEntityEncoder : EntityEncoder[Login] = jsonEncoderOf[Login]
I was able to solve this. I did a search on google on sbt circe dependency and I copy pasted the first search result. that was circe 0.1 and that is why things were not working for me.
I changed my dependencies to
libraryDependencies ++= Seq(
"org.http4s" %% "http4s-core" % http4sVersion,
"org.http4s" %% "http4s-dsl" % http4sVersion,
"org.http4s" %% "http4s-blaze-client" % http4sVersion,
"org.http4s" %% "http4s-circe" % http4sVersion,
"io.circe" %% "circe-core" % "0.7.0",
"io.circe" %% "circe-generic" % "0.7.0"
)
and now automatic derivation works fine and I am able to compile the code below
import org.http4s.client.blaze.SimpleHttp1Client
import org.http4s._
import org.http4s.headers._
import org.http4s.circe._
import scalaz.concurrent.Task
import io.circe.syntax._
import io.circe.generic.auto._
import org.http4s.Status.ResponseClass.Successful
case class Login(username: String, password: String)
case class Token(token: String)
object JsonHelpers {
implicit val loginEntityEncoder : EntityEncoder[Login] = jsonEncoderOf[Login]
implicit val loginEntityDecoder : EntityDecoder[Login] = jsonOf[Login]
implicit val tokenEntityEncoder: EntityEncoder[Token] = jsonEncoderOf[Token]
implicit val tokenEntityDecoder : EntityDecoder[Token] = jsonOf[Token]
}
object Http4sTest2 extends App {
import JsonHelpers._
val url = "http://"
val uri = Uri.fromString(url).valueOr(throw _)
val list = List[Header](`Content-Type`(MediaType.`application/json`), `Accept`(MediaType.`application/json`))
val request = Request(uri = uri, method = Method.POST)
.withBody(Login("foo", "bar").asJson)
.map{r => r.replaceAllHeaders(list :_*)}.run
val client = SimpleHttp1Client()
val result = client.fetch[Option[Token]](request){
case Successful(response) => response.as[Token].map(Some(_))
case _ => Task(Option.empty[Token])
}.run
println(result)
}