user5407287 user5407287 - 4 months ago 32
JSON Question

JSON Read/Write Error: Application Does Not Take Parameters

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.

Answer

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`