0

Below is my simple document that represents a Link. I am using reactivemongo in scala for this.

I am getting this error during compilation:

app/components/Link.scala:60:11: No Json deserializer found for type components.Link. Try to implement an implicit Reads or Format for this type. [error] .one[Link]) [error] ^ [error] one error found

I created the implicits in my Link companion object, which I also imported into my LinkRepo class.

Am I handling the mongo document _id correctly?
Should I use a String to map to the document ID, confused as to what is the best practise? Do I have to convert the String to the BSONObjectID at some point?

package components

import javax.inject.Inject
import reactivemongo.bson._

import reactivemongo.api.ReadPreference
import reactivemongo.api.collections.bson.BSONCollection
import reactivemongo.bson.{ BSONDocument, BSONObjectID }
import reactivemongo.api.commands.{ UpdateWriteResult, WriteResult, Upserted }
import reactivemongo.api.commands.bson.BSONUpdateCommand._
import reactivemongo.api.commands.bson.BSONUpdateCommandImplicits._

case class Link(id: Link.ID,
                name: String,
                url: String)


object Link {

  type ID = String

  implicit val linkReader: BSONDocumentReader[Link] =
    BSONDocumentReader[Link] { doc: BSONDocument =>
      Link(
        doc.getAs[String]("id").getOrElse(""),
        doc.getAs[String]("name").getOrElse(""),
        doc.getAs[String]("url").getOrElse(""))
    }

  implicit val linkWriter: BSONDocumentWriter[Link] =
    BSONDocumentWriter[Link] { link: Link =>
      BSONDocument(
        "id" -> link.id,
        "name" -> link.name,
        "url" -> link.url)
    }

}

import scala.concurrent.{ ExecutionContext, Future }
import reactivemongo.bson.{ BSONDocument, BSONObjectID }

import reactivemongo.api.{ Cursor, ReadPreference }
import reactivemongo.api.commands.WriteResult

import reactivemongo.play.json._
import reactivemongo.play.json.collection.JSONCollection

import play.modules.reactivemongo.ReactiveMongoApi

class LinkRepo @Inject()(implicit ec: ExecutionContext, reactiveMongoApi: ReactiveMongoApi) {
  import Link._

  def linksCol: Future[JSONCollection] = reactiveMongoApi.database.map(_.collection("links"))

  def byId(id: Link.ID): Future[Option[Link]] = {
    linksCol.flatMap(_.find(
      selector = BSONDocument("_id" -> id),
      projection = Option.empty[BSONDocument])
      .one[Link])
  }



}

My sbt has these lib versions:

scalaVersion := "2.12.7"

libraryDependencies += guice
libraryDependencies ++= Seq(
  guice,
  "joda-time" % "joda-time" % "2.9.9",
  "net.ruippeixotog" %% "scala-scraper" % "2.1.0",
  "org.reactivemongo"      %% "play2-reactivemongo" % "0.16.0-play26",
  "org.scalatestplus.play" %% "scalatestplus-play" % "3.1.2" % Test
)

plugins:

addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.20")
Blankman
  • 259,732
  • 324
  • 769
  • 1,199
  • 1
    You're using a JSON collection, but the provided one are BSON, so you need to make sure conversions from `ImplicitBSONHandlers` is imported from `reactivemongo.play.json`. – cchantep Jan 03 '19 at 16:19
  • I added both ```import reactivemongo.play.json.ImplicitBSONHandlers``` and ```import reactivemongo.play.json._``` but I still get the same error. – Blankman Jan 03 '19 at 16:37
  • Check the versions – cchantep Jan 03 '19 at 16:38
  • @cchantep I added my versions to my question. I'm using reactivemongo 0.16.0-play26. – Blankman Jan 04 '19 at 12:46

1 Answers1

1

As far as I know, you do not NEED TO use BSONObjectID, but it would be recommended. But one thins you should use "_id" field in mongo, otherwise the default behaviour will be to create an _id on your document when you create a new one... so your document will have _id and id.

So you should get id from "_id" and write it into "_id" even if your case class is id.

As per handlers, for basic case classes you can use their provided macros:

implicit val linkHandler: BSONDocumentHandler[Link] = Macros.handler

this will generate the Reader and Writer for your Link.

When using the macros, you have an annotations that you can use to highlight your id will be "_id" on mongo:

import reactivemongo.bson.Macros.Annotations.Key

case class Link(
  @Key("_id")
  id: Link.ID,
  name: String,
  url: String
)
FerranJr
  • 332
  • 1
  • 8
  • But since I have my own handler in this case, why isn't it finding the implicit? – Blankman Jan 03 '19 at 15:30
  • I realise you are using JSONCollection.. this is specific of Play... which I guess converts the BSON into JSON so you are not providing Json readers for thos documents... but not sure as I haven't use reactiveMongo with play, I use it in akka-http... sorry about that – FerranJr Jan 03 '19 at 16:36