3

I'm trying to update some of my old Scala code to new APIs.

In one of the libraries I use, a case class has been converted to a simple POJO for compatibility reasons.

I was wondering if it is still possible somehow to use pattern matching for the Java class.

Imagine I have a simple Java class like:

public class A {
    private int i;

    public A(int i) {
        this.i = i;
    }

    public int getI() {
        return i;
    }
}

After compilation, I would like to use it in pattern matching somehow like:

class Main extends App {
    val a = ...

    a match {
        case _ @ A(i) =>
            println(i);
    }
}

For the code above, I obviously get an error: Main.scala:7: error: object A is not a case class constructor, nor does it have an unapply/unapplySeq method.

Is there any trick I could use here?

Thanks in advance!

rlegendi
  • 10,466
  • 3
  • 38
  • 50

3 Answers3

3

It's a little late in the night here for subtlety, but

object `package` {
  val A = AX
}

object AX {
  def unapply(a: A): Option[Int] = Some(a.getI)
}

object Test extends App {
  Console println {
    new A(42) match {
      case A(i) => i
    }
  }
}
som-snytt
  • 39,429
  • 2
  • 47
  • 129
1

Write unapply yourself:

object A {
    def unapply(x: A) = Some(x.getI)
}
  • 1
    Hm... Now this looks interesting. You sure this should work? I get some real exotic errors like `constructor is defined twice conflicting symbols...`, `constructor not allowed here` and `self constructor arguments cannot reference unconstructed this`. Let me play around with them so we can see how far I get :-) – rlegendi Nov 09 '14 at 21:58
  • @som-snytt Thanks, but my issue is not about `unapply()` :-) Have you tried compiling something above where `A` is a POJO? – rlegendi Nov 10 '14 at 08:13
  • 1
    You can't define companions in separate files in scala, let alone java interop. Otherwise, the extractor name is arbitrary. See http://stackoverflow.com/questions/4921827/in-scala-how-can-i-define-a-companion-object-for-a-class-defined-in-java – som-snytt Nov 10 '14 at 08:49
1

@som-snytt's answer is correct - but if you are doing this just for e.g. pattern-matching then I prefer the more succinct approach:

import spray.httpx.{UnsuccessfulResponseException => UrUnsuccessfulResponseException}

object UnsuccessfulResponseException {
  def unapply(a: UrUnsuccessfulResponseException): Option[HttpResponse]
    = Some(a.response)
}

... match {
  case Failure(UnsuccessfulResponseException(r)) => r
  case ...
}

Ur is a pretentious way of saying "original", but it only takes two letters.

Alex Dean
  • 15,575
  • 13
  • 63
  • 74