Рассмотрим этот JSON:
{
"myDocument": {
"static_key": "value",
"dynamic_key": "value",
"static_key2": "value2",
"dynamic_key2": {
"dynamic_key3": "value3"
}
}
}
Документы JSON, которые я собираюсь обработать, имеют некоторые статические ключи (поля, которые, как я знаю, будут присутствовать всегда), но имеют некоторые другие, которые могут бытьили не присутствовать, с заранее неизвестными именами для сопоставления их некоторым case class
.
У меня есть абсолютный путь к полю в строке (извлекается из конфигурации, хранящейся в базе данных) со следующей структурой:
"myDocument.dynamic_key2.dynamic_key3"
Я знаю, что мне нужно иметь ADT для отображения туда и обратно, поэтому я пришел к следующему:
sealed trait Data
final case class StringTuple(key: String, value: String) extends Data
object StringTuple {
implicit val encoder: Encoder[StringTuple] = deriveEncoder[StringTuple]
implicit val decoder: Decoder[StringTuple] = deriveDecoder[StringTuple]
}
final case class NumericTuple(key: String, value: Double) extends Data
object NumericTuple {
implicit val encoder: Encoder[NumericTuple] = deriveEncoder[NumericTuple]
implicit val decoder: Decoder[NumericTuple] = deriveDecoder[NumericTuple]
}
final case class DateTuple(key: String, value: OffsetDateTime) extends Data
object DateTuple {
implicit val encoder: Encoder[DateTuple] = deriveEncoder[DateTuple]
implicit val decoder: Decoder[DateTuple] = deriveDecoder[DateTuple]
}
final case class TransformedJson(data: Data*)
object TransformedJson {
def apply(data: Data*): TransformedJson = new TransformedJson(data: _*)
implicit val encoder: Encoder[TransformedJson] = deriveEncoder[TransformedJson]
implicit val decoder: Decoder[TransformedJson] = deriveDecoder[TransformedJson]
}
На основании этого обсуждение , нет смысла использовать Map[String, Any]
с circe, поэтому я разделил три возможных случая значения ключа, с которыми я столкнусь при разборе отдельных полей:
- Числовое поле, что я собираюсь проанализировать как
Double
. - Поле String проанализировано как есть (
String
). - Поле даты проанализировано как
OffsetDateTime
.
По этой причине я создал три класса дел, которые моделируют этиКомбинации (NumericTuple
, StringTuple
и DateTuple
), и моя идея состоит в том, чтобы создать вывод JSON, подобный этому:
{
"dynamic_key": "extractedValue",
"dynamic_key3": "extractedValue3",
...
}
("Обычный", без вложенности вообще).
Моя идея состоит в том, чтобы создать список Data
объектов для достижения этой цели, и у меня есть что-то вроде этого:
def extractValue(confElement: Conf, json: String) = {
val cursor: HCursor = parse(json).getOrElse(Json.Null).hcursor
val decodeDynamicParam = Decoder[NumericTuple].prepare(
/*
Here I think (not sure) that I can extract the value with the decoder,
but, how can I extract the key name and set it, alongside with the extracted
value?
*/
_.downField(confElement.path)
)
}
Некоторые соображения:
- На основании ответа Трэвиса на этот вопрос Я пытаюсь смоделировать JSON как можно ближе для работы с Circe.Вот почему я пытался использовать модель tuples .
- Основываясь (опять же) на ответе Тревиса на этот вопрос SO , я пытаюсь использовать метод
Decode.prepare(...)
.И вот возникает мой вопрос ...
Вопрос: Как мне извлечь конкретное имя клавиши текущей позиции курсора и сопоставить его с Tuple
?Мне нужен только текущий ключ, а не весь набор ключей, который возвращает .keys
метод ACursor
.С помощью этого ключа я хочу вручную отобразить кортеж с текущим именем ключа и извлеченным значением.
Для подведения итогов мне нужно преобразовать структуру, имеющую некоторые неизвестные ключи (имя и положение),извлеките их значения на основе пути, разделенного абсолютной точкой, и поднимите как имя ключа, так и имя значения в классе дел, который я добавил как Tuple
.
Можете ли вы пролить свет на это??
Спасибо