Я использую ReactiveMongo 0.11.11 для Play 2.5 и хочу преобразовать BSONDocument в JsObject.BSONDocument to JsObject и переопределить BSONDateTimeFormat
Для большинства типов данных BSON (String, Int ...) значения по умолчанию отлично подходят для работы библиотеки. Для типа BSON DateTime (BSONDateTime
) значение свойства JSON не дает мне формат, который мне нужен.
Значение JSON для даты является JSObject с именем свойства $date
и метку времени UNIX в миллисекундах, как его значение:
{
"something": {
"$date": 1462288846873
}
}
JSON Я хочу, чтобы это строковое представление Дата вроде этого:
{
"something": "2016-05-03T15:20:46.873Z"
}
К сожалению, я не знаю, как переопределить поведение по умолчанию, не переписывая все или не меняя код в самой библиотеке.
Это где я думаю, что это происходит (source code):
val partialWrites: PartialFunction[BSONValue, JsValue] = {
case dt: BSONDateTime => Json.obj("$date" -> dt.value)
}
Моя версия бы выглядеть следующим образом:
val partialWrites: PartialFunction[BSONValue, JsValue] = {
case dt: BSONDateTime =>
JsString(Instant.ofEpochMilli(dt.value).toString)
}
Можно ли переопределить этот бит?
Я создал эксперимент ...
import java.time.Instant
import play.api.libs.json._
import reactivemongo.bson._
import reactivemongo.play.json.BSONFormats.BSONDocumentFormat
object Experiment {
// Original document (usually coming from the database)
val bson = BSONDocument(
"something" -> BSONDateTime(1462288846873L) // equals "2016-05-03T15:20:46.873Z"
)
// Reader: converts from BSONDateTime to JsString
implicit object BSONDateTimeToJsStringReader extends BSONReader[BSONDateTime, JsString] {
def read(bsonDate: BSONDateTime): JsString = {
JsString(Instant.ofEpochMilli(bsonDate.value).toString)
}
}
// Reader: converts from BSONDateTime to JsValue
implicit object BSONDateTimeToJsValueReader extends BSONReader[BSONDateTime, JsValue] {
def read(bsonDate: BSONDateTime): JsValue = {
JsString(Instant.ofEpochMilli(bsonDate.value).toString)
}
}
// Read and print specific property "something" using the `BSONReader`s above
def printJsDate = {
val jsStr: JsString = bson.getAs[JsString]("something").get
println(jsStr) // "2016-05-03T15:20:46.873Z"
val jsVal: JsValue = bson.getAs[JsValue]("something").get
println(jsVal) // "2016-05-03T15:20:46.873Z"
}
// Use ReactiveMongo's default format to convert a BSONDocument into a JsObject
def printAsJsonDefault = {
val json: JsObject = BSONDocumentFormat.writes(bson).as[JsObject]
println(json) // {"something":{"$date":1462288846873}}
// What I want: {"something":"2016-05-03T15:20:46.873Z"}
}
}
Я хотел бы отметить, что преобразование BSONDateTime в JsValue всегда должен работать, когда я конвертировать BSONDocument в JSObject, а не только тогда, когда я вручную выбрать конкретный известное свойство. Это означает, что свойство «что-то» в моем примере может иметь любое имя и также отображаться в поддоку.
BTW: В случае, если вы задаетесь вопросом, я вообще работаю с коллекциями BSON в своем проекте Play, но я не думаю, что это имеет значение в этом случае.
Редактировать
Я попытался предоставления Writes[BSONDateTime]
, но, к сожалению, не используется, и я до сих пор получить тот же результат, как и раньше. Код:
import java.time.Instant
import play.api.libs.json._
import reactivemongo.bson.{BSONDocument, BSONDateTime}
object MyImplicits {
implicit val dateWrites = Writes[BSONDateTime] (bsonDate =>
JsString(Instant.ofEpochMilli(bsonDate.value).toString)
)
// I've tried this too:
// implicit val dateWrites = new Writes[BSONDateTime] {
// def writes(bsonDate: BSONDateTime) = JsString(Instant.ofEpochMilli(bsonDate.value).toString)
// }
}
object Experiment {
// Original document (usually coming from the database)
val bson = BSONDocument("something" -> BSONDateTime(1462288846873L))
// Use ReactiveMongo's default format to convert a BSONDocument into a JsObject
def printAsJson = {
import reactivemongo.play.json.BSONFormats.BSONDocumentFormat
import MyImplicits.dateWrites // import is ignored
val json: JsObject = BSONDocumentFormat.writes(bson).as[JsObject]
//val json: JsValue = Json.toJson(bson) // I've tried this too
println(json) // {"something":{"$date":1462288846873}}
}
}
Большое спасибо за ваш ответ! Я применил 'Writes [BSONDateTime]', как вы предлагали, но, похоже, его игнорируют. См. Редактирование в моем вопросе. Я как-то чувствую, что это потому, что я использую 'BSONDocumentFormat'. У тебя есть идеи? – Nick
Попробуйте 'println (s" writer = $ {неявно [Записывает [BSONDateTime]]} ")' – cchantep
Отпечатки: 'writer = play.api.libs.json.Writes $$ anon $ 6 @ b9c81b0' – Nick