pitchblack408
pitchblack408

Reputation: 2983

How to use ReactiveMongoDB and doc.getAs with a complex object?

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

Upvotes: 0

Views: 616

Answers (1)

pitchblack408
pitchblack408

Reputation: 2983

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)))
  } 



}  

Upvotes: 1

Related Questions