Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error : spray.json.SerializationException: Map key must be formatted as JsString, not '["A","b"]' #217

Open
ontologiae opened this issue Jan 10, 2017 · 7 comments

Comments

@ontologiae
Copy link

Hi, I defined an object as follow :
case class Obj(a: String, b: Map[String, List[String]], c: String, d : Int, f : Map[(String,String), (Float,Float)])

All the config for spray worked until I add Map[(String,String), (Float,Float)]

println(Obj("id", Map( "Rule1" -> List("el1","el2")), "srcRep", 1, Map( (("A","b")) -> ((0.5f,1.2f)) ) ).toJson)
Here's the stacktrace :

Exception in thread "main" spray.json.SerializationException: Map key must be formatted as JsString, not '["A","b"]'
	at spray.json.CollectionFormats$$anon$3$$anonfun$write$3.apply(CollectionFormats.scala:53)
	at spray.json.CollectionFormats$$anon$3$$anonfun$write$3.apply(CollectionFormats.scala:50)
	at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
	at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
	at scala.collection.immutable.Map$Map1.foreach(Map.scala:116)
	at scala.collection.TraversableLike$class.map(TraversableLike.scala:234)
	at scala.collection.AbstractTraversable.map(Traversable.scala:104)
	at spray.json.CollectionFormats$$anon$3.write(CollectionFormats.scala:50)
	at spray.json.CollectionFormats$$anon$3.write(CollectionFormats.scala:48)
	at spray.json.ProductFormats$class.productElement2Field(ProductFormats.scala:46)
	at com.xxxxxx.JsonProtocols$.productElement2Field(JsonConversion.scala:6)
	at spray.json.ProductFormatsInstances$$anon$5.write(ProductFormatsInstances.scala:126)
	at spray.json.ProductFormatsInstances$$anon$5.write(ProductFormatsInstances.scala:118)
	at spray.json.PimpedAny.toJson(package.scala:39)
	at com.xxxxxxx.MainGenere$.delayedEndpoint$com$xxxxxx$xxxxx$MainGenere$1(MainGenere.scala:415)
@klpx
Copy link

klpx commented Feb 6, 2017

Tuple2 is encoded as JSON array. And JSON array could not be an JSON object key.
You can create your own JsonFormat[(String, String)] which will serialize tuple as string ("str1,str2" for example), but in this case you can't import all of DefaultJsonFormat._ because it already have deserizlier for Tuple2[T1 : JsonFormat, T2 : JsonFormat]

@l15k4
Copy link

l15k4 commented Dec 6, 2017

For me this workaround doesn't work :

object Foo extends DefaultJsonProtocol {
  import spray.json._

  case class CampKey(value: String) extends AnyVal
  case class DataPointKey(value: String) extends AnyVal
  case class DataPointValue(value: String) extends AnyVal
  type DataMap                = Map[CampKey, Map[DataPointKey, Set[DataPointValue]]]

  implicit object dataPointKeyFormat extends RootJsonReader[DataPointKey] { def read(json: JsValue): DataPointKey = DataPointKey(json.asInstanceOf[JsString].value) }
  implicit object dataPointValueFormat extends RootJsonReader[DataPointValue] { def read(json: JsValue): DataPointValue = DataPointValue(json.asInstanceOf[JsString].value) }
  implicit object campKeyFormat extends RootJsonReader[CampKey] { def read(json: JsValue): CampKey = CampKey(json.asInstanceOf[JsString].value) }

  implicitly[JsonReader[DataMap]] //  Cannot find JsonReader or JsonFormat type class for DataMap

But JsonReader implicit is not resolved for DataMap

@lustefaniak
Copy link

That would work:

object Foo {
  import spray.json._
  case class CampKey(value: String)        extends AnyVal
  case class DataPointKey(value: String)   extends AnyVal
  case class DataPointValue(value: String) extends AnyVal
  type DataMap = Map[CampKey, Map[DataPointKey, Set[DataPointValue]]]

  implicit object dataPointKeyFormat extends RootJsonFormat[DataPointKey] {
    def read(json: JsValue): DataPointKey          = DataPointKey(json.asInstanceOf[JsString].value)
    override def write(obj: DataPointKey): JsValue = JsString(obj.value)
  }
  implicit object dataPointValueFormat extends RootJsonFormat[DataPointValue] {
    def read(json: JsValue): DataPointValue          = DataPointValue(json.asInstanceOf[JsString].value)
    override def write(obj: DataPointValue): JsValue = JsString(obj.value)
  }
  implicit object campKeyFormat extends RootJsonFormat[CampKey] {
    def read(json: JsValue): CampKey          = CampKey(json.asInstanceOf[JsString].value)
    override def write(obj: CampKey): JsValue = JsString(obj.value)
  }

  implicit val dataPointValueSetFormat = new RootJsonFormat[Set[DataPointValue]] {
    def write(items: Set[DataPointValue]) = JsArray(items.map(_.toJson).toVector)
    def read(value: JsValue) = value match {
      case JsArray(elements) => elements.map(_.convertTo[DataPointValue]).toSet[DataPointValue]
      case x                 => deserializationError("Expected Array as JsArray, but got " + x)
    }
  }

  implicit val dataMapEntryFormat = DefaultJsonProtocol.mapFormat[DataPointKey, Set[DataPointValue]]
  implicit val dataMapRootReader  = DefaultJsonProtocol.mapFormat[CampKey, Map[DataPointKey, Set[DataPointValue]]]
}

@lustefaniak
Copy link

And you should probably change reads, to get rid of asInstanceOf, and fail with DeserializationException using deserializationError if value is not JsString.

@l15k4
Copy link

l15k4 commented Dec 7, 2017

Yeah I did not want to discourage people from reading it as they usually give up on snippets longer that xx lines and I would decrease my changes on getting help :-)

@chenshaoxing
Copy link

import spray.json._
import spray.json.DefaultJsonProtocol._

val list = Map("k"->"f","n"->"r","d"->ListInt)
println(list.toJson)

compiler error: Cannot find JsonWriter or JsonFormat type class for scala.collection.immutable.Map[String,java.io.Serializable]

I used wrong?

@raboof
Copy link
Contributor

raboof commented Mar 22, 2019

@chenshaoxing you crossposted at #292, I answered there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants