1

I'm trying to write a Read/Write value for a case class for which many of the values might be null. Following the Play Framework's tutorials I write it as

implicit val incomingMessageWrites: Writes[IncomingMessage] = (
        (JsPath \ "stageNum").write[Int] and
        (JsPath \ "stage").write[String] and
        (JsPath \ "stageTime").write[Long] and
        (JsPath \ "vendorId").write[String] and
        (JsPath \ "text").writeNullable[String] and
        (JsPath \ "campaignCode").writeNullable[String] and
        (JsPath \ "osTotals").writeNullable[OSTotals] and
        (JsPath \ "splitSegment").writeNullable[Int] and
        (JsPath \ "segmentNum").writeNullable[Int] and
        (JsPath \ "osBatchStatus").writeNullable[OSBatchStatus]
    )(unlift(IncomingMessage.unapply))

However, I keep encountering the same issue where IntelliJ tells me that the uplift method doesn't work because "Application Does Not Take Parameters".

The case class for this is

case class IncomingMessage(
  stageNum: Int,
  stage: String,
  stageTime: Long,
  vendorId: String,
  text: String,
  campaignCode: String,
  osTotals: OSTotals,
  splitSegment: Int,
  segmentNum: Int,
  osBatchStatus: OSBatchStatus) {

    def this(stageNum: Int, stage: String, stageTime: Long, vendorId: String, text: String, campaignCode: String) =
      this(stageNum, stage, stageTime, vendorId, text, campaignCode, null, 0, 0, null)

    def this(stageNum: Int, stage: String, stageTime: Long, splitSegment: Int, vendorId: String, text: String, campaignCode: String) =
      this(stageNum, stage, stageTime, vendorId, text, campaignCode, null, splitSegment, 0, null)

    def this(stageNum: Int, stage: String, stageTime: Long, segmentNum: Int, vendorId: String) =
      this(stageNum, stage, stageTime, vendorId, null, null, null, 0, segmentNum, null)

    def this(stageNum: Int, stage: String, stageTime: Long, segmentNum: Int, vendorId: String, osTotals: OSTotals) =
      this(stageNum, stage, stageTime, vendorId, null, null, osTotals, 0, segmentNum, null)

    def this(stageNum: Int, stage: String, stageTime: Long, vendorId: String, oSBatchStatus: OSBatchStatus) =
      this(stageNum, stage, stageTime, vendorId, null, null, null, 0, 0, osBatchStatus)

}

The same thing happens for the other case class

case class OSBatchStatus(os: String, success: Int, failure: Int)

object OSBatchStatus {
  implicit val oSBatchStatusReads: Reads[OSBatchStatus] = (
    (JsPath \ "os").readNullable[String] and
      (JsPath \ "success").readNullable[Int] and
      (JsPath \ "failure").readNullable[Int]
    )(OSBatchStatus.apply _)
}

I've written Read and Write values, but have omitted them to save space.

Any and all help would be greatly appreciated.

1 Answer 1

2

If there are optional fields in your input JSON file, then the corresponding fields of your case class should be optional as well. Your definition of Reads for OSBatchStatus assumes that all fields are optional, so your case class should look like this:

case class OSBatchStatus(os: Option[String], success: Option[Int], failure: Option[Int])

The same rules apply to your IncomingMessage case class (four fields are obligatory and every other should be an Option[T]). Moreover, since the fields in your JSON file have exactly the same names as the fields in your case class, you can use play-json methods that will autogenerate Reads/Writes/Format for you:

import play.api.libs.functional.syntax._
import play.api.libs.json._

implicit val incomingMessageWrites = Json.writes[IncomingMessage]
implicit val osBatchStatusReads    = Json.reads[OSBatchStatus]
implicit val osTotalsFormat        = Json.format[OSTotals] // Will generate both `Reads` and `Writes`
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.