Play / Scala JSON format for Either

I have a value class that accepts Either , which I would like to create for playback for Scala v2.5.6 JSON Format for:

 import org.joda.time.{DateTime, Duration} case class When(when: Either[DateTime, Duration]) extends AnyVal 

I think the writes method is clarified; The problems I'm having are related to the reads method. I tried to do two approaches, both refused for various reasons.

Attempt # 1 showing reads and writes methods:

 import play.api.libs.json._ import play.api.libs.json.Json.obj object When { def apply(dateTime: DateTime): When = When(Left(dateTime)) def apply(duration: Duration): When = When(Right(duration)) implicit val whenFormat = new Format[When] { def reads(json: JsValue): JsResult[When] = { val reads = (__ \ "dateTime").read[Long] { (millis: Long) => When(Left(new DateTime(millis))) } | (__ \ "duration").read[Long] { (millis: Long) => When(Right(new Duration(millis))) } reads.reads(json) } def writes(o: When): JsValue = obj( o.when.fold( duration => "duration" -> duration.getMillis, dateTime => "dateTime" -> dateTime.getMillis ) ) } } 

Error messages:

 overloaded method value read with alternatives: [error] (t: Long)play.api.libs.json.Reads[Long] <and> [error] (implicit r: play.api.libs.json.Reads[Long])play.api.libs.json.Reads[Long] [error] cannot be applied to (Long => When) [error] val reads = (__ \ "dateTime").read[Long] { (millis: Long) => [error] overloaded method value read with alternatives: [error] (t: Long)play.api.libs.json.Reads[Long] <and> [error] (implicit r: play.api.libs.json.Reads[Long])play.api.libs.json.Reads[Long] [error] cannot be applied to (Long => When) [error] } | (__ \ "duration").read[Long] { (millis: Long) => 

Try # 2 by simply showing the reads method:

 def reads(json: JsValue): JsResult[When] = JsSuccess( When(Left(new DateTime((__ \ "dateTime").read[Long]))) || When(Right(new Duration((__ \ "duration").read[Long]))) ) 

Error message:

 value || is not a member of When [error] Note: implicit value whenFormat is not applicable here because it comes after the application point and it lacks an explicit result type [error] Error occurred in an application involving default arguments. 

I just like something that works, and I donโ€™t care which approach is used (even the one I didnโ€™t show), provided that it is supported and effective. It would also be useful to know what is wrong with each of these approaches.

+5
source share
1 answer

Here is an example of how to do this:

 import org.joda.time.{DateTime, Duration} import play.api.libs.functional.syntax._ import play.api.libs.json.Reads._ import play.api.libs.json._ object When { def apply(dateTime: DateTime): When = When(Left(dateTime)) def apply(duration: Duration): When = When(Right(duration)) val reads: Reads[When] = (__ \ "dateTime").read[Long].map(millis => When(Left(new DateTime(millis)))) | (__ \ "duration").read[Long].map(millis => When(Right(new Duration(millis)))) val writes: Writes[When] = new Writes[When] { override def writes(o: When): JsValue = Json.obj( o.when.fold( duration => "duration" -> duration.getMillis, dateTime => "dateTime" -> dateTime.getMillis ) ) } implicit val format = Format(reads, writes) } 

basically you have to display readings

 (__ \ "dateTime").read[Long] 

gives you Reads[Long] , then you can match the result with When . You just passed a parameter. This parameter can be Long to simply ignore what it read and return this value, or implicit reads for a long time that you probably do not want to change, and should leave it implicit.

Thus, in a similar way, you can create another reading for the duration and combine them with an alternative ( | ) and make you read.

Your second approach does not make sense. Either use reading and compiling, or just manually check if there is something, and if you do not return another result, but this is not worth doing, just use the default approach.

+6
source

All Articles