0

I am working with the Play framework and ReactiveMongoDB. I am trying to write a reader and a writer for my class called Customer. This is all being done in the models.scala file in the following order:

import reactivemongo.bson._


case class StreetAddressLine(
  id: Option[BSONObjectID],
  StreetAddressLine: String,
  creationDate: Option[DateTime],
  updateDate: Option[DateTime])

object StreetAddressLine {
  implicit object StreetAddressLineBSONReader extends BSONDocumentReader[StreetAddressLine] {
    def read(doc: BSONDocument): StreetAddressLine =
      StreetAddressLine(
        doc.getAs[BSONObjectID]("_id"), 
        doc.getAs[String]("StreetAddressLine").get, 
        doc.getAs[BSONDateTime]("creationDate").map(dt => new DateTime(dt.value)),
        doc.getAs[BSONDateTime]("updateDate").map(dt => new DateTime(dt.value)))
 }
}  



case class PrimaryAddress(
  id: Option[BSONObjectID],
  StreetAddressLine: List[StreetAddressLine],
  PrimaryTownName: String,
  CountryISOAlpha2Code: String,
  PostalCode: String,
  PostalCodeExtensionCode: String,
  TerritoryOfficialName: String,
  TerritoryAbbreviatedName: String,
  creationDate: Option[DateTime],
  updateDate: Option[DateTime])

object PrimaryAddress {
  implicit object PrimaryAddressBSONReader extends BSONDocumentReader[PrimaryAddress] {
    def read(doc: BSONDocument): PrimaryAddress =
      PrimaryAddress(
        doc.getAs[BSONObjectID]("_id"), //Mongos internal identifier
        doc.getAs[List[StreetAddressLine]]("StreetAddressLine").get, 
        doc.getAs[String]("PrimaryTownName").get,        
        doc.getAS[String]("CountryISOAlpha2Code").get, 
        doc.getAS[String]("PostalCode").get,      
        doc.getAs[String]("PostalCodeExtensionCode").get,  
        doc.getAs[String]("TerritoryOfficialName").get,     
        doc.getAs[String]("TerritoryAbbreviatedName").get,  
        doc.getAs[BSONDateTime]("creationDate").map(dt => new DateTime(dt.value)),
        doc.getAs[BSONDateTime]("updateDate").map(dt => new DateTime(dt.value)))
  }
}  

But I am getting an error

[error] C:\Users\xxxxx\git\oneid-scala\oneid-scala\app\models\models.scala:54:
 value getAS is not a member of reactivemongo.bson.BSONDocument
[error]         doc.getAS[String]("CountryISOAlpha2Code").get,
[error]             ^
[error] C:\Users\xxxxx\git\oneid-scala\oneid-scala\app\models\models.scala:55:
 value getAS is not a member of reactivemongo.bson.BSONDocument
[error]         doc.getAS[String]("PostalCode").get,
[error]  

for the following lines

doc.getAS[String]("PostalCode").get,      
doc.getAs[String]("PostalCodeExtensionCode").get,

I decided to add the writers in

package models

import org.jboss.netty.buffer._
import org.joda.time.DateTime
import play.api.data._
import play.api.data.Forms._
import play.api.data.format.Formats._
import play.api.data.validation.Constraints._

import reactivemongo.bson._





case class StreetAddressLine(
  id: Option[BSONObjectID],
  StreetAddressLine: String,
  creationDate: Option[DateTime],
  updateDate: Option[DateTime])

object StreetAddressLine {
  implicit object StreetAddressLineBSONReader extends BSONDocumentReader[StreetAddressLine] {
    def read(doc: BSONDocument): StreetAddressLine =
      StreetAddressLine(
        doc.getAs[BSONObjectID]("_id"), 
        doc.getAs[String]("StreetAddressLine").get, 
        doc.getAs[BSONDateTime]("creationDate").map(dt => new DateTime(dt.value)),
        doc.getAs[BSONDateTime]("updateDate").map(dt => new DateTime(dt.value)))
 }
 implicit object StreetAddressLineBSONWriter extends BSONDocumentWriter[StreetAddressLine] {
    def write(streetAddressLine: StreetAddressLine): BSONDocument =
      BSONDocument(
        "_id" -> streetAddressLine.id.getOrElse(BSONObjectID.generate),
        "StreetAddressLine" -> streetAddressLine.StreetAddressLine,
        "creationDate" -> streetAddressLine.creationDate.map(date => BSONDateTime(date.getMillis)),
        "updateDate" -> streetAddressLine.updateDate.map(date => BSONDateTime(date.getMillis)))
  } 

}  



case class PrimaryAddress(
  id: Option[BSONObjectID],
  StreetAddressLine: List[StreetAddressLine],
  PrimaryTownName: String,
  CountryISOAlpha2Code: String,
  PostalCode: String,
  PostalCodeExtensionCode: String,
  TerritoryOfficialName: String,
  TerritoryAbbreviatedName: String,
  creationDate: Option[DateTime],
  updateDate: Option[DateTime])

object PrimaryAddress {

 implicit object PrimaryAddressBSONReader extends BSONDocumentReader[PrimaryAddress] {
   def read(doc: BSONDocument): PrimaryAddress =
     PrimaryAddress(
       doc.getAs[BSONObjectID]("_id"), 
       doc.getAs[String]("StreetAddressLine").get, 
       doc.getAs[String]("PrimaryTownName").get,
       doc.getAs[String]("CountryISOAlpha2Code").get, 
       doc.getAs[String]("PostalCode").get, 
       doc.getAs[String]("PostalCodeExtensionCode").get, 
       doc.getAs[String]("TerritoryOfficialName").get, 
       doc.getAs[String]("TerritoryAbbreviatedName").get, 
       doc.getAs[BSONDateTime]("creationDate").map(dt => new DateTime(dt.value)),
       doc.getAs[BSONDateTime]("updateDate").map(dt => new DateTime(dt.value)))
 }  


 implicit object PrimaryAddressBSONWriter extends BSONDocumentWriter[PrimaryAddress] {
    def write(primaryAddress: PrimaryAddress): BSONDocument =
      BSONDocument(
        "_id" -> primaryAddress.id.getOrElse(BSONObjectID.generate),
        "StreetAddressLine" -> primaryAddress.StreetAddressLine,
        "PrimaryTownName" -> primaryAddress.PrimaryTownName,
        "CountryISOAlpha2Code" -> primaryAddress.CountryISOAlpha2Code,
        "PostalCode" -> primaryAddress.PostalCode,
        "TerritoryOfficialName" -> primaryAddress.TerritoryOfficialName,
        "TerritoryAbbreviatedName" -> primaryAddress.TerritoryAbbreviatedName,
        "creationDate" -> primaryAddress.creationDate.map(date => BSONDateTime(date.getMillis)),
        "updateDate" -> primaryAddress.updateDate.map(date => BSONDateTime(date.getMillis)))
  } 



}  

And the compile error changed to the following

[info] Compiling 2 Scala sources to C:\Users\xxxxx\git\oneid-scala\oneid-scala
\target\scala-2.11\classes...
[error] C:\Users\xxxxx\git\oneid-scala\oneid-scala\app\models\models.scala:62:
 type mismatch;
[error]  found   : String
[error]  required: List[models.StreetAddressLine]
[error]  Note: implicit object PrimaryAddressBSONWriter is not applicable here b
ecause it comes after the application point and it lacks an explicit result type

[error]        doc.getAs[String]("StreetAddressLine").get,
[error]                                               ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 4 s, completed Jul 11, 2015 12:40:20 PM
pitchblack408
  • 2,913
  • 4
  • 36
  • 54
  • If you look at the [documentation](http://reactivemongo.org/releases/0.11/documentation/bson/typeclasses.html), you would see how to define readers/writers for your own types. It's not possible to define a reader parsing a property whose type (there `PrimaryAddress`) is not previously provided itself as reader. – cchantep Jul 11 '15 at 00:09
  • cchantep thank you. I changed the code above to include a definition for a reader for the included custom class StreetAddressLine, but it is still erroring out. What am I missing? – pitchblack408 Jul 11 '15 at 18:36
  • Check compilation message – cchantep Jul 11 '15 at 18:39
  • I just added the exact lines that I got after running the activator compile command – pitchblack408 Jul 11 '15 at 18:52

1 Answers1

1

Thank you cchantep, the following code compiles now. I found that there are two parts to the answer here.

A. In order to have embedded custom classes in another class, each class defined must be defined.

B. Both the writers and readers must have been defined for all classes or there will be compiler errors. You can't just defined the readers without the writers.

The following code compiles fine

package models

import org.jboss.netty.buffer._
import org.joda.time.DateTime
import play.api.data._
import play.api.data.Forms._
import play.api.data.format.Formats._
import play.api.data.validation.Constraints._

import reactivemongo.bson._





case class StreetAddressLine(
  id: Option[BSONObjectID],
  StreetAddressLine: String,
  creationDate: Option[DateTime],
  updateDate: Option[DateTime])

object StreetAddressLine {
  implicit object StreetAddressLineBSONReader extends BSONDocumentReader[StreetAddressLine] {
    def read(doc: BSONDocument): StreetAddressLine =
      StreetAddressLine(
        doc.getAs[BSONObjectID]("_id"), 
        doc.getAs[String]("StreetAddressLine").get, 
        doc.getAs[BSONDateTime]("creationDate").map(dt => new DateTime(dt.value)),
        doc.getAs[BSONDateTime]("updateDate").map(dt => new DateTime(dt.value)))
 }
 implicit object StreetAddressLineBSONWriter extends BSONDocumentWriter[StreetAddressLine] {
    def write(streetAddressLine: StreetAddressLine): BSONDocument =
      BSONDocument(
        "_id" -> streetAddressLine.id.getOrElse(BSONObjectID.generate),
        "StreetAddressLine" -> streetAddressLine.StreetAddressLine,
        "creationDate" -> streetAddressLine.creationDate.map(date => BSONDateTime(date.getMillis)),
        "updateDate" -> streetAddressLine.updateDate.map(date => BSONDateTime(date.getMillis)))
  } 

}  



case class PrimaryAddress(
  id: Option[BSONObjectID],
  StreetAddressLine: List[StreetAddressLine],
  PrimaryTownName: String,
  CountryISOAlpha2Code: String,
  PostalCode: String,
  PostalCodeExtensionCode: String,
  TerritoryOfficialName: String,
  TerritoryAbbreviatedName: String,
  creationDate: Option[DateTime],
  updateDate: Option[DateTime])

object PrimaryAddress {

 implicit object PrimaryAddressBSONReader extends BSONDocumentReader[PrimaryAddress] {
   def read(doc: BSONDocument): PrimaryAddress =
     PrimaryAddress(
       doc.getAs[BSONObjectID]("_id"), 
       doc.getAs[List[StreetAddressLine]]("StreetAddressLine").get, 
       doc.getAs[String]("PrimaryTownName").get,
       doc.getAs[String]("CountryISOAlpha2Code").get, 
       doc.getAs[String]("PostalCode").get, 
       doc.getAs[String]("PostalCodeExtensionCode").get, 
       doc.getAs[String]("TerritoryOfficialName").get, 
       doc.getAs[String]("TerritoryAbbreviatedName").get, 
       doc.getAs[BSONDateTime]("creationDate").map(dt => new DateTime(dt.value)),
       doc.getAs[BSONDateTime]("updateDate").map(dt => new DateTime(dt.value)))
 }  



 implicit object PrimaryAddressBSONWriter extends BSONDocumentWriter[PrimaryAddress] {
    def write(primaryAddress: PrimaryAddress): BSONDocument =
      BSONDocument(
        "_id" -> primaryAddress.id.getOrElse(BSONObjectID.generate),
        "StreetAddressLine" -> primaryAddress.StreetAddressLine,
        "PrimaryTownName" -> primaryAddress.PrimaryTownName,
        "CountryISOAlpha2Code" -> primaryAddress.CountryISOAlpha2Code,
        "PostalCode" -> primaryAddress.PostalCode,
        "TerritoryOfficialName" -> primaryAddress.TerritoryOfficialName,
        "TerritoryAbbreviatedName" -> primaryAddress.TerritoryAbbreviatedName,
        "creationDate" -> primaryAddress.creationDate.map(date => BSONDateTime(date.getMillis)),
        "updateDate" -> primaryAddress.updateDate.map(date => BSONDateTime(date.getMillis)))
  } 



}  
pitchblack408
  • 2,913
  • 4
  • 36
  • 54
  • I had a similar problem and I was able to make it compile fine using this answer. However, it seems like the readers and writers are not really called at runtime. Any ideas? – redwulf Mar 08 '16 at 10:40