2016-04-02 8 views
7

の配列のために、故障わからない、これはバグですが、次のデモは、最終的な例で失敗:はスプレーJSON Eithers

import spray.json._ 
import DefaultJsonProtocol._ 

object SprayTest { 
    1.toJson 
    "".toJson 
    (Left(1): Either[Int, String]).toJson 
    (Right(""): Either[Int, String]).toJson 
    Seq(1).toJson 
    Seq("").toJson 
    Seq(Left(1), Right("")).toJson 
    Seq(Left(1), Right("")).toJson(seqFormat(eitherFormat(IntJsonFormat, StringJsonFormat))) 
} 

だから、すべてのビルディング・ブロックが動作しているように見えますが、フォーマットの構成SeqEitherの場合は、たとえそれをスプーンフィードしようとしても失敗します。私は次のエラーが表示

[error] SprayTest.scala:11: Cannot find JsonWriter or JsonFormat type class for Seq[Product with Serializable with scala.util.Either[Int,String]] 
[error] Seq(Left(1), Right("")).toJson 
[error]       ^
[error] SprayTest.scala:12: type mismatch; 
[error] found : spray.json.DefaultJsonProtocol.JF[Either[Int,String]] 
[error]  (which expands to) spray.json.JsonFormat[Either[Int,String]] 
[error] required: spray.json.JsonFormat[Product with Serializable with scala.util.Either[Int,String]] 
[error] Note: Either[Int,String] >: Product with Serializable with scala.util.Either[Int,String] (and spray.json.DefaultJsonProtocol.JF[Either[Int,String]] <: spray.json.JsonFormat[Either[Int,String]]), but trait JsonFormat is invariant in type T. 
[error] You may wish to define T as -T instead. (SLS 4.5) 
[error] Seq(Left(1), Right("")).toJson(seqFormat(eitherFormat(IntJsonFormat, StringJsonFormat))) 

与えるもの任意のアイデア?

答えて

14

これは、両方のProductSerializableが、Either自体はひどい推測されたタイプにつながる、ない拡張Either -the LeftRightコンストラクタについての最も厄介なものの一つです:

scala> Seq(Left(1), Right("")) 
res0: Seq[Product with Serializable with scala.util.Either[Int,String]] = List(Left(1), Right()) 

JsonFormatがあるので、その型パラメータで不変である場合、Aのインスタンスがあるということは、Product with Serializable with Aのインスタンスがあることを意味しません。具体的には、具体的には、実際にはEither[Int, String]のインスタンスがありますが、推論された型の余分なガベージコレクションは、コンパイラが見つけられないことを意味します。

あなたが順番にRightを持っていない場合も、同様のことが起こる:

scala> Seq(Left(1), Left(2)).toJson 
<console>:18: error: Cannot find JsonWriter or JsonFormat type class for Seq[scala.util.Left[Int,Nothing]] 
     Seq(Left(1), Left(2)).toJson 
          ^

あなたはタイプを提供する代わりに、推論いずれかを使用して、両方の問題を解決することができます

scala> val xs: Seq[Either[Int, String]] = Seq(Left(1), Right("")) 
xs: Seq[Either[Int,String]] = List(Left(1), Right()) 

scala> xs.toJson 
res1: spray.json.JsValue = [1,""] 

多くの場合、これは問題ではありません。LeftRightを直接使用するのではなく、Eitherの値をEitherで明示的に返すメソッドから取得することが多いためですこの問題につながる。

脚注として、独自のADTを定義しているときは、常にルートシールされた特性(またはシールされたクラス)をProduct with Serializableに拡張する必要があります。標準的なライブラリの設計者がそのアドバイスに従っていれば、私たちはずっと良くなっています。

+0

ここで私の例を修正しましたが、残念ながら実際のコードは修正されません。(しかし、非常に参考になりました。 – acjay

2

あなたはそれをコンパイルしますSeqsの要素に型ascriptionsを追加した場合、私は思う:私は問題だと思う

(Seq(Left(1), Right("")): Either[Int, String]).toJson 
(Seq(Left(1), Right("")): Either[Int, String]).toJson(seqFormat(eitherFormat(IntJsonFormat, StringJsonFormat)) 

Seq(Left(1): Either[Int, String], Right(""): Either[Int, String]).toJson 
Seq(Left(1): Either[Int, String], Right(""): Either[Int, String]).toJson(seqFormat(eitherFormat(IntJsonFormat, StringJsonFormat)) 

は、あなたもそれを単一タイプの帰属を与えることができますscalacは、単一の型を派生させるためにSeqに提供する要素間の共通の最小の境界を決定しようとしています(標準的なコレクションでは要素の同種のデータ型が必要なため)助けて。 scala標準ライブラリにSerializableをextends Productで定義した場合、これを行う必要はありませんが、右と左の両方のサブタイプが暗黙のうちにProductとSerializableを拡張しているので、それらは含まれます推論型ではスプレーで必要とされる不変型の問題を引き起こしています。

+0

はTravisが私にそれを打つように見える。 :-) –

関連する問題