Codec for ADT do not compile - mongodb

I'm using the scala driver to make IO operations with mongodb. My scala version is 2.11.11 and the mongo db driver is 2.2.0.
I take the example in documentation about ADT :
sealed class Tree
case class Branch(b1: Tree, b2: Tree, value: Int) extends Tree
case class Leaf(value: Int) extends Tree
val codecRegistry = fromRegistries( fromProviders(classOf[Tree]), DEFAULT_CODEC_REGISTRY )
This code didn't compile.
No known subclasses of the sealed class
[error] val codecRegistry = fromRegistries( fromProviders(classOf[Tree]), DEFAULT_CODEC_REGISTRY )
[error] ^
[error] knownDirectSubclasses of Tree observed before subclass Branch registered
[error] knownDirectSubclasses of Tree observed before subclass Leaf registered
Did I miss something ?
Update
Below a complete example of what I'm tring to do.
build.sbt
name := "mongodb-driver-test"
version := "1.0"
scalaVersion := "2.11.11"
libraryDependencies += "org.mongodb.scala" %% "mongo-scala-driver" % "2.2.0"
file Models.scala
import org.mongodb.scala.bson.codecs.{DEFAULT_CODEC_REGISTRY, Macros}
import org.bson.codecs.configuration.CodecRegistries.{fromProviders, fromRegistries}
/**
* Created by alifirat on 02/01/18.
*/
object Models {
sealed class Tree
case class Branch(b1: Tree, b2: Tree, value: Int) extends Tree
case class Leaf(value: Int) extends Tree
val treeCodec = Macros.createCodecProvider[Tree]()
val treeCodecRegistry = fromRegistries( fromProviders(treeCodec), DEFAULT_CODEC_REGISTRY )
}
Then, just do :
sbt compile
You will get :
[error] val treeCodec = Macros.createCodecProvider[Tree]()
[error] ^
[error] knownDirectSubclasses of Tree observed before subclass Branch registered
[error] knownDirectSubclasses of Tree observed before subclass Leaf registered
[error] three errors found
[error] (compile:compileIncremental) Compilation failed
If I change the scala version to 2.12.0, I didn't have any errors at compile time ...

I'm using driver version 2.6.0 and Scala version 2.12.8 and still get the same problem.
My workaround is to remove the keyword sealed in front of that sealed class, compile, put it back, and then compile again. But it's very cumbersome.

Related

Symbol 'type cats.MonadFilter' is missing fromthe classpath

I am reading this tutorial on tagless final.
Based on this I have defined my dependencies as
object Dependencies {
lazy val scalaTest = "org.scalatest" %% "scalatest" % "3.0.5"
lazy val cats = "org.typelevel" %% "cats-core" % "1.2.0"
lazy val monix = "io.monix" %% "monix" % "2.3.3"
lazy val monixCats = "io.monix" %% "monix-cats" % "2.3.3"
}
The following is my code
// future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.concurrent.duration._
// cats
import cats.Monad
import cats.implicits._
// monix
import monix.eval.Task
import monix.cats._
import monix.cats.reverse._
trait ProductRepository[M[_]] {
def findProduct(productId: ProductId) : M[Option[Product]]
def saveProduct(product: Product) : M[Unit]
def incrementProductSales(productId: ProductId, quantity: Long) : M[Unit]
}
class ProductRepositoryWithFuture extends ProductRepository[Future] {
def findProduct(productId: ProductId) : Future[Option[Product]] = {
Future.successful(Some(Product(productId, "foo")))
}
def saveProduct(product: Product) : Future[Unit] = {
Future.successful()
}
def incrementProductSales(productId: ProductId, quanity: Long) : Future[Unit] = {
Future.successful()
}
}
class ProductRepositoryWithTask extends ProductRepository[Task] {
def findProduct(productId: ProductId) : Task[Option[Product]] = {
Task.now(Some(Product(productId, "foo")))
}
def saveProduct(product: Product) : Task[Unit] = {
Task.unit
}
def incrementProductSales(productId: ProductId, quantity: Long) : Task[Unit] = {
Task.unit
}
}
But I get bunch of errors. It seems that the version of cats which I am using is not compatible with the one Monix uses.
I also tried to remove my cats dependency and just imported monix so that monix pulls in its own version of cats. but even that doesn't compile.
error] /Users/foobar/code/tagless/src/main/scala/example/Hello.scala:54:24: Symbol 'type cats.MonadFilter' is missing fromthe classpath.
[error] This symbol is required by 'method monix.cats.MonixToCatsCore7.monixToCatsMonadFilter'.
[error] Make sure that type MonadFilter is in your classpath and check for conflicting dependencies with `-Ylog-classpath`.
[error] A full rebuild may help if 'MonixToCatsCore7.class' was compiled against an incompatible version of cats.
[error] repo.findProduct(id).flatMap{
[error] ^
[error] /Users/foobar/code/tagless/src/main/scala/example/Hello.scala:54:23: diverging implicit expansion for type monix.types.Comonad[M]
[error] starting with method catsToMonixComonad in trait CatsCoreToMonix5
[error] repo.findProduct(id).flatMap{
[error] ^
[error] /Users/foobar/code/tagless/src/main/scala/example/Hello.scala:54:28: value flatMap is not a member of type parameter M[Option[example.Application.Product]]
[error] repo.findProduct(id).flatMap{
[error] ^
[error] /Users/foobar/code/tagless/src/main/scala/example/Hello.scala:56:30: value copy is not a member of Any
[error] val newProduct = p.copy(name = name)
[error] ^
[error] /Users/foobar/code/tagless/src/main/scala/example/Hello.scala:56:40: reassignment to val
[error] val newProduct = p.copy(name = name)
[error] ^
[error] /Users/foobar/code/tagless/src/main/scala/example/Hello.scala:57:27: diverging implicit expansion for type monix.types.MonadError[M,E]
[error] starting with method catsToMonixMonadError in trait CatsCoreToMonix3
[error] repo.saveProduct(newProduct).map(_ => Some(p))
[error] ^
[error] /Users/foobar/code/tagless/src/main/scala/example/Hello.scala:57:40: value map is not a member of type parameter M[Unit]
[error] repo.saveProduct(newProduct).map(_ => Some(p))
[error] ^
[error] /Users/foobar/code/tagless/src/main/scala/example/Hello.scala:59:16: diverging implicit expansion for type cats.Comonad[M]
[error] starting with method monixToCatsComonad in trait MonixToCatsCore5
[error] Monad[M].pure(None)
[error] ^
[error] 8 errors found
The errors are caused by incompatibilities between your dependencies.
For example monix 2.3.3 depends on cats 0.9.0 while you're trying to use 1.2.0 which is binary incompatible.
You should try either upgrading monix to 3.x or downgrading cats to 0.9.0.
P.S. The transition from cats 0.9.0 to 1.x has a lot of breaking changes and you have to make sure that all libraries you're using are compiled against the same (or at least binary compatible) version of cats.

custom timestamp extractor in kafka streams

I'm trying to use kafka streams to process some data from a kafka topic. The data comes from kafka topic that was written to by kafka 0.11.0 something which doesn't have the embedded timestamp. After some reading on the internet, I came to understand that I can solve this problem by extending TimestampExtractor class in a custom class and passing it in the StreamsConfig.
I did so like this --
class MyEventTimestampExtractor extends TimestampExtractor {
override def extract(record: ConsumerRecord[AnyRef, AnyRef], prev: Long) = {
record.value() match {
case w: String => 1000L
case _ => throw new RuntimeException(s"Called for $record")
}
}
}
I based it off of this code on github
But, I get this error when I do an sbt run
[error] /home/someuser/app/blahblah/src/main/scala/main.scala:34: class MyEventTimestampExtractor needs to be abstract, since method extract in trait TimestampExtractor of type (x$1: org.apache.kafka.clients.consumer.ConsumerRecord[Object,Object], x$2: Long)Long is not defined
[error] (Note that Long does not match Long)
[error] class MyEventTimestampExtractor extends TimestampExtractor {
[error] ^
[error] /home/someuser/app/blahblah/src/main/scala/main.scala:35: method extract overrides nothing.
[error] Note: the super classes of class MyEventTimestampExtractor contain the following, non final members named extract:
[error] def extract(x$1: org.apache.kafka.clients.consumer.ConsumerRecord[Object,Object],x$2: Long): Long
[error] override def extract(record: ConsumerRecord[AnyRef, AnyRef], prev: Long): Long = {
[error] ^
[error] two errors found
[error] (compile:compileIncremental) Compilation failed
My build.sbt file is this --
name := "kafka streams experiment"
version := "1.0"
scalaVersion := "2.12.4"
libraryDependencies ++= Seq(
"org.apache.kafka" % "kafka-streams" % "1.0.0"
)
I don't really understand the error. Specifically the part around Note that Long does not match Long. What could I be doing wrong? thanks!
You need java.Long since this API is defined in Java whereas you are using Scala Long
Try with (watch the type of the prev function argument:
override def extract(record: ConsumerRecord[AnyRef, AnyRef], prev: java.lang.Long) = {

Not found : Type Build (Unresolved 'Build')

I'm getting the following set of errors, which I belive is caused by the sbt-assembly plugin that I is used.
In fact the object declaration of ;
object Build extends **Build** { (here Build is unresolved).
The error is as follows,
Error:Error while importing SBT project:<br/><pre>
[info] Loading settings from assembly.sbt,plugins.sbt ...
[info] Loading project definition from C:\Users\ShakthiW\IdeaProjects\TestProject\project
[error] <path>\Build.scala:4:22: not found: type Build
[error] object Build extends Build{
[error] ^
[error] <path>\Build.scala:8:80: value map is not a member of (sbt.TaskKey[sbt.librarymanagement.UpdateReport], sbt.SettingKey[java.io.File], sbt.SettingKey[String])
[error] def copyDepTask = copyDependencies <<= (update, crossTarget, scalaVersion) map {
[error] ^
[error] <path>\Build.scala:19:16: too many arguments (3) for method apply: (id: String, base: java.io.File)sbt.Project in object Project
[error] Note that 'settings' is not a parameter name of the invoked method.
[error] settings = Defaults.defaultSettings ++ Seq(
[error] ^
[error] three errors found
[error] (compile:compileIncremental) Compilation failed
A quick resolve is highly appreciated.
My Build.scala looks like this.
import sbt.Keys._
import sbt._
object MyBuild extends Build {
lazy val copyDependencies = TaskKey[Unit]("copy-dependencies")
def copyDepTask = copyDependencies <<= (update, crossTarget, scalaVersion) map {
(updateReport, out, scalaVer) =>
updateReport.allFiles foreach { srcPath =>
val destPath = out / "lib" / srcPath.getName
IO.copyFile(srcPath, destPath, preserveLastModified=true)
}
}
lazy val root = Project(
"root",
file("."),
settings = Defaults.defaultSettings ++ Seq(
copyDepTask
)
)
}
Also, I do rekon there is a issue with sbt-assembly upgrades as well which I'm not entirely aware of.
In sbt version 1.0.x, some key dependencies operators were removed. See the migration docs: https://www.scala-sbt.org/0.13/docs/Migrating-from-sbt-012x.html
Here is an short tutorial for writing Build.scala for sbt version 1.0.x: https://alvinalexander.com/scala/sbt-how-to-use-build.scala-instead-of-build.sbt.
You can also refer to build.scala of an existing project for more ref, eg. scalaz.

SBT cannot resolve class declared in src/main/scala in a src/test/scala test class

I am trying to make my own custom CSV reader. I am using IntelliJ IDEA 14 with sbt and specs2 test framework.
The class I declared in src/main is as follows:
import java.io.FileInputStream
import scala.io.Source
class CSVStream(filePath:String) {
val csvStream = Source.fromInputStream(new FileInputStream(filePath)).getLines()
val headers = csvStream.next().split("\\,", -1)
}
The content of the test file in src/test is as follows:
import org.specs2.mutable._
object CSVStreamSpec {
val csvSourcePath = getClass.getResource("/csv_source.csv").getPath
}
class CSVStreamSpec extends Specification {
import CSVStreamLib.CSVStreamSpec._
"The CSV Stream reader" should {
"Extract the header" in {
val csvSource = CSVStream(csvSourcePath)
}
}
}
The build.sbt file contains the following:
name := "csvStreamLib"
version := "1.0"
scalaVersion := "2.11.4"
libraryDependencies ++= Seq("org.specs2" %% "specs2-core" % "2.4.15" % "test")
parallelExecution in Test := false
The error I am getting when I type test is as follows:
[error] /Users/raiyan/IdeaProjects/csvStreamLib/src/test/scala/csvStreamSpec.scala:18: not found: value CSVStream
[error] val csvSource = CSVStream(csvSourcePath)
[error] ^
[error] one error found
[error] (test:compile) Compilation failed
[error] Total time: 23 s, completed 30-Dec-2014 07:44:46
How do I make the CSVStream class accessible to the CSVStreamSpec class in the test file?
Update:
I tried it with sbt in the command line. The result is the same.
You forgot the new keyword. Without it, the compiler looks for the companion object named CSVStream, not the class. Since there is none, it complains. Add new and it'll work.

Writing a custom matcher for NodeSeq

I'm trying to write a simple custom matcher for NodeSeq, with scalatest v.2.0.M5b.
package test
import org.scalatest.matchers.{MatchResult, Matcher, ShouldMatchers}
import scala.xml.NodeSeq
import org.scalatest.FunSpec
class MySpec extends FunSpec with ShouldMatchers with MyMatcher {
describe("where is wrong?") {
it("showOK") {
val xml = <span>abc</span>
xml should contn("b")
}
}
}
trait MyMatcher {
class XmlMatcher(str: String) extends Matcher[NodeSeq] {
def apply(xml: NodeSeq) = {
val x = xml.toString.contains(str)
MatchResult(
x,
"aaa",
"bbb"
)
}
}
def contn(str: String) = new XmlMatcher(str)
}
When I compile it, it reports error:
[error] /Users/freewind/src/test/scala/test/MyMacher.scala:14: overloaded method value should with alternatives:
[error] (beWord: MySpec.this.BeWord)MySpec.this.ResultOfBeWordForAnyRef[scala.collection.GenSeq[scala.xml.Node]] <and>
[error] (notWord: MySpec.this.NotWord)MySpec.this.ResultOfNotWordForAnyRef[scala.collection.GenSeq[scala.xml.Node]] <and>
[error] (haveWord: MySpec.this.HaveWord)MySpec.this.ResultOfHaveWordForSeq[scala.xml.Node] <and>
[error] (rightMatcher: org.scalatest.matchers.Matcher[scala.collection.GenSeq[scala.xml.Node]])Unit
[error] cannot be applied to (MySpec.this.XmlMatcher)
[error] xml should contn("b")
[error] ^
[error] one error found
[error] (test:compile) Compilation failed
Where is wrong?
Update:
The build.sbt file I use:
name := "scalatest-test"
scalaVersion := "2.10.1"
version := "1.0"
resolvers ++= Seq("snapshots" at "http://oss.sonatype.org/content/repositories/snapshots",
"releases" at "http://oss.sonatype.org/content/repositories/releases",
"googlecode" at "http://sass-java.googlecode.com/svn/repo"
)
libraryDependencies += "org.scalatest" %% "scalatest" % "2.0.M5b" % "test"
And a demo project: https://github.com/freewind/scalatest-test
For the reason why scala compiler complains see this answer.
But it seems that ScalaTest API has changed quite a bit since then, so the two solutions proposed both need some modification (tested for ScalaTest 2.0.M5b):
Replace All instances of NodeSeq to GenSeq[Node] so that the type matches everywhere.
See SeqShouldWrapper class of ScalaTest.
Alternatively, wrap xml explicitely with the conversion function, i.e. manually setting the required type but I don't recommend this because it makes client code ugly.
new AnyRefShouldWrapper(xml).should(contn("b"))
BTW, it is good to have a small but complete project on github for others to tweak. It makes this question much more attractive.