2

ScalaでJackson JSON オブジェクトに対してパターン マッチングを実行できるかどうか疑問に思っています。私たちは現在、プロジェクトでjackson-module-scalaを多用しており、Json ObjectNode/JsonNode オブジェクトのパターン マッチングを実行できるとメリットがあります。

これが不可能な場合、この機能を追加するにはどうすればよいですか? JsonNode/ObjectNode からMyClassMyClass にunapplyメソッドがあり、 JsonNode.toString と正規表現マッチングを行う への暗黙的な変換に関して何かを考えていました。私のロジックが正しければ、JsonNode オブジェクトでパターン マッチングを行うことができます。もちろん、私が気付いていないより良い方法があるかもしれませんし、私がまだ気付いていない理由でこの方法がうまくいかないかもしれません。私のケースを説明するために、次の点で何かを実行できるようにしたいと考えています。

val mapper = new ObjectMapper()
mapper.registerModule(DefaultScalaModule)

val json = mapper.createObjectNode()
                .put("key1","value1")
                .put("key2","value2")
                .put("key3","value3")

json match {
  case MyClass("key1", "value1", "key2", y) => println("Found key1 with value1, where key2 is " + y)
  case MyClass("key1", x) => println("Key1 value is " + x)
  ...
  _ => println("No match found")
}
4

1 に答える 1

3

ケースクラスの逆シリアル化を利用しようとしましたか? https://github.com/FasterXML/jackson-module-scala/blob/master/src/test/scala/com/fasterxml/jackson/module/scala/deser/CaseClassDeserializerTest.scala

それがうまくいかない場合は、ドメイン オブジェクトを表すエクストラクタを作成する方がよいと思います。以下のコードは、scala Map を想定していますが、アイデアが得られるはずです。暗黙的な変換は必要ありません。

case class DomainObjectA(v1: String, v2: String)
object DomainObjectAExtractor {
  def unapply(m: Map[String, String]) = for {
     v1 <- m.get("key1")
     v2 <- m.get("key2")
  } yield DomainObjectA(v1, v2)
}

case class DomainObjectB(v3, v4, v5)
object DomainObjectBExtractor {
  def unapply(m: Map[String, String]) = for {
     v3 <- m.get("key3")
     v4 <- m.get("key4")
     v5 <- m.get("key5")
  } yield DomainObjectB(v3, v4, v5)
}

json match {
  case DomainObjectAExtractor(a@DomainObjectA(_, _)) => a
  case DomainObjectBExtractor(b@DomainObjectB(_, _, _)) => b
}

ただし、キーと値のペアに対して一致を試みることに固執する場合は、許容できることを達成する方法があるかもしれません。からunapply関数に入力を渡すことはできません。これはcase、あなたが何をしたいのかを正しく理解している場合に必要になると思います。これは、まもなく正式にリリースされる scala 2.10 で実験的なマクロを使用して実行できる可能性があります。しかし、これが可能かどうかを知るのに十分なほど彼らと遊んだことはありません.

::キーの順序付けが想定されている場合、for listに似た unapply 演算子を考え出すことができます::K, Vこれにより、この既知の順序でペアを抽出できます。個人的には、これは私の好みには壊れやすいです。

val json = Map(("key1" -> "one"), ("key2" -> "two"))

object -> {
  def unapply[A, B](ab: (A, B)) = Some(ab)
}

object :: {
  def unapply[K, V](m: Map[K, V]): Option[((K, V), Map[K, V])] = 
    m.headOption.map(_ -> m.tail)
}

scala> json match {
     |   case ("key1" -> "one") :: ("key2" -> value2) :: _ => value2
     | }
res0: java.lang.String = two

ただし、間違った順序でキーを抽出することはできません

scala> json match {
     |   case ("key2" -> value2) :: _ => value2
     |   case _ => "match fail"
     | }
res2: java.lang.String = match fail

Key1、、とKey2書くこともできKey3ます。これは、適切にスケーリングされる場合とそうでない場合があります。

object && {
  def unapply[A](a: A) = Some((a, a))
}

object Key2 {
  def unapply[V](m: Map[String, V]) = m.get("key2")
}

object Key1 {
  def unapply[V](m: Map[String, V]) = m.get("key1")
}

scala> json match {
     |   case Key2(value2) && Key1(value1) => (value2, value1)
     | }
res5: (java.lang.String, java.lang.String) = (two,one)
于 2012-12-02T02:07:10.137 に答える