英文:
How to convert a map to json where one of the types is AnyRef
问题
我有一个类型为[String, AnyRef]
的Map。如何使用play-json将其转换为Json?我找到了一些答案,但它们都定义了一个类型。当我尝试进行转换时,我得到了编译器错误消息:
> 没有隐式参数的类型:Writes[Map[String, AnyRef]]
val testMap: Map[String, AnyRef] = Map.empty[String, AnyRef]
假设此地图具有以下数据:
{ "lastModifiedTime" -> 1575311400000,
"user_id" -> 1,
"user_email" -> "user@email.com",
"is_active" -> true,
"project_id" -> 1,
"status" -> "COMPLETED" }
所以我的问题是,如果我在地图中将AnyRef作为第二类型,如何只使用play-Json将其转换为Json?
更正 =>
此地图是作为Elasticsearch结果的一部分获得的,因此我不能保证每次地图都相同,但它们将是相同类型的地图,即Map[String, AnyRef]。
英文:
I have a Map which is of the type [String, AnyRef]
. How do i convert it to Json using play-json. I found some answers but they all had a type defined. When i tried converting i got the compiler error message as:
> No implicit arguments of type: Writes[Map[String, AnyRef]]
val testMap: Map[String, AnyRef] = Map.empty[String, AnyRef]
Suppose this map has the following data:
{ "lastModifiedTime" -> 1575311400000,
"user_id" -> 1,
"user_email" -> "user@email.com",
"is_active" -> true,
"project_id" -> 1,
"status"-> "COMPLETED" }
So my question is if I have AnyRef as the second type in map how will I convert it to Json using just play-Json ?
Correction => <br/>
This map is obtained as a result of elastic search result, so i cannot guarantee that every time the map will be same, but it will be of the same type that is, Map[String, AnyRef].
答案1
得分: 3
Play-json试图尽可能类型安全,这意味着它无法为Map[String, AnyRef]
提供隐式序列化器。这可能会遮盖其他序列化器,无法确保它不会失败。您可以创建自己的序列化器,但它将是硬编码的,您不应该将其放在全局范围内:
// 在这里开始编写你的ScalaFiddle代码
import play.api.libs.json._
val testMap = Map[String, Any](
"test" -> 1,
"otherTest" -> "denada",
"mapsAlsoWorksSomehow" -> Map (
"wee" -> true,
"mapsEverywhere" -> Map (
"wee" -> false, "prr" -> new java.util.Date(),
),
"ops" -> new java.lang.Integer(22)
)
)
// 你可以创建一个函数,只需将对象映射到JsValues,而不使用类型...
// 不安全,但有效
def toJsValue(a: Any): JsValue = a match {
case v: JsValue => v
case v: Map[String, _] => JsObject(v.map { case (k, v) => (k, toJsValue(v)) }) //请记住,我们假设这是[String,Any]的映射,否则它会失败 :(
case v: String => JsString(v)
case v: Int => JsNumber(v)
case v: Boolean => JsBoolean(v)
case v: java.util.Date => JsString(v.toString)
case v if v == null => JsNull
}
implicit lazy val anyWriter: Writes[Map[String, Any]] = new Writes[Map[String, Any]] {
def writes(a: Map[String, Any]): JsValue = toJsValue(a)
}
println(Json.toJson(testMap))
println(toJsValue(testMap))
// 这里我们隐式使用了anyWriter,但还有其他的... 目前被遮盖了 :(。
println(Json.toJson(testMap.mapValues[JsValue] { case (v) => toJsValue(v) }))
但请记住,当您在Map中有不受支持的类型时,它会失败。我猜最好的方法是不创建隐式写入器,而是在Map的参数上使用toJsValue
方法,然后尝试序列化它(就像最后的println
中一样)。
如果这有帮助,请投票并标记为答案。
英文:
Play-json try to be as typesafe as possible and this means it cannot provide implicitly serializer for Map[String, AnyRef]
. It could shadow other serializers and it couldn't ensure it will not fail. You can create your own but it'll be hard-coded and you should not put it in your globals:
// Start writing your ScalaFiddle code here
import play.api.libs.json._
val testMap = Map[String,Any](
"test" -> 1,
"otherTest" -> "denada",
"mapsAlsoWorksSomehow" -> Map (
"wee" -> true,
"mapsEverywhere" -> Map (
"wee" -> false, "prr" -> new java.util.Date(),
),
"ops" -> new java.lang.Integer(22)
)
)
//you can create your own function that just maps objects to JsValues without using types...
//not safe but works
def toJsValue(a:Any):JsValue = a match {
case v:JsValue => v
case v:Map[String,_] => JsObject(v.map { case (k,v) => (k, toJsValue(v)) }) //keep in mind we assume this is map of [String,Any] if not it will blow up :(
case v:String => JsString(v)
case v:Int => JsNumber(v)
case v:Boolean => JsBoolean(v)
case v:java.util.Date => JsString(v.toString)
case v if v == null => JsNull
}
implicit lazy val anyWriter:Writes[Map[String,Any]] = new Writes[Map[String,Any]] {
def writes(a:Map[String,Any]):JsValue = toJsValue(a)
}
println(Json.toJson(testMap))
println(toJsValue(testMap))
//here we use anyWriter implicitly but there is other one... currently shadowed :(.
println(Json.toJson(testMap.mapValues[JsValue] { case (v) => toJsValue(v) }))
But keep in mind that it will blow up when You will have unsupported type in Map. I guess best way is not to create implicit writer but use toJsValue
method on arguments of a map and then try to serialize it (like in last println
).
If it was helpful, up-vote please and mark as answer.
答案2
得分: 1
最简单的选项是将所有的值转换为 String
并保存。
val stringMap = testMap.mapValues(_.toString)
如果无法实现这个,您要么必须为 AnyRef
创建一个自定义处理程序,要么手动从 Map
创建一个 JObject
,并使用 match
来选择每个元素的特定 JSON 类型。
英文:
The simplest option is to convert all the values to String
and save that.
val stringMap = testMap.mapValues(_.toString)
Failing that you either have to create a custom handler for AnyRef
or manually create a JObject
from the Map
and use match
to select the specific JSON type for each element.
答案3
得分: 0
你不能这样做。
你可以拥有的最接近 AnyRef
的东西是 play.api.libs.json.JsValue
。
换句话说,你需要一个类似于 JSON
的对象结构,其中包含 Writers 或 Readers。
如果需要更多解释,请告诉我。
英文:
You cannot do that.
The closest thing to AnyRef
you can have is play.api.libs.json.JsValue
.
Or in other words you need a JSON
-like object structure, where you have Writers, resp. Readers.
Let me know if you need further explanation.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论