简体   繁体   中英

Is it possible to get a Scala case class for an exisiting Java bean class?

The short story of the question is in the title. There is some Java class eg org.joda.time.Interval and I'd like to (without rewriting it) make it a case class ie so that is has the apply and unapply methods.

Long story: I have a Scala-Play application and there I define a form that takes two intervals ie

import org.joda.time.Interval

case class MyParams(param1: String, interval1: Interval, interval2: Interval)

and then I attempt to define the nested mapping but Interval is a Java class and doesn't have apply / unapply and I'd rather not create my own copy.

val myForm = Form {
      mapping(
        "param1" -> nonEmptyText,
        "interval1" -> mapping(
          "start" -> jodaDate,
          "end" -> jodaDate,
        )(Interval.apply)(Interval.unapply), // <<<<<<<<<< Cannot resolve symbol ...
        "interval2" -> mapping(
          "start" -> jodaDate,
          "end" -> jodaDate,
        )(Interval.apply)(Interval.unapply) // <<<<<<<<<< Cannot resolve symbol ...
    )(MyParams.apply)(MyParams.unapply)
}

Of course, I could flatten the structure but doing so doesn't scale well design-wise plus there are existing JSON composite structures that will need the composition and I'd like to reuse the form to bind to both JSON requests and form submits.

UPDATE building on top of the accepted answer and taking syntactic sugar into account I did at the end:

object IntervalUtils {
  implicit object Interval {
    def apply(start: DateTime, end: DateTime) = new org.joda.time.Interval(start, end)
    def unapply(interval: org.joda.time.Interval) = Some((interval.getStart, interval.getEnd))
  }
}

so the code of the OP compiles as is only missing the import IntervalUtils._ and then as added bonus can also do:

implicit val jodaIntervalWrites = new Writes[org.joda.time.Interval] {
  def writes(interval: org.joda.time.Interval) = Json.obj(
    "start" -> interval.getStart,
    "end" -> interval.getEnd
  )
}

implicit val jodaIntervalReads: Reads[org.joda.time.Interval] = (
    (JsPath \ "start").read[DateTime] and
    (JsPath \ "end").read[DateTime]
  )(Interval.apply _) // <<<<<<<<<<<<<<<<<< reused here

To do this, you don't need a case class, you just need two methods with suitable signatures, and you can define them easily:

object JodaTime {
  def mkInterval(start: ReadableInstant, end: ReadableInstant) = new Interval(start, end)
  def unmkInterval(interval: Interval) = Some((interval.getStart, interval.getEnd))
}

// elsewhere
mapping(
  "start" -> jodaDate,
  "end" -> jodaDate,
)(JodaTime.mkInterval)(JodaTime.unmkInterval)

In fact, you don't even need mkInterval , you can just write new Interval(_, _) (not sure if overloads can cause a problem for this specific use-case, but if so just specify the placeholder types).

一种解决方案可能是使用apply和unapply(以及您可能希望复制的其他方法)创建一个隐式类,模拟一个案例类: http : //docs.scala-lang.org/overviews/core/implicit-classes .html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM