Я использую Argonaut для анализа объектов от удаленного поставщика JSON. API имеет два типа конечных точек: традиционный запрос REST по URL-адресу и ответ одного объекта JSON. Я могу легко анализировать сложные возвращаемые объекты JSON с помощью Argonaut на этом типе конечной точки.
Моя проблема связана с конечной точкой потоковой передачи поставщика, которая возвращает случайные объекты JSON из ограниченного набора JSON для данной конечной точки. Объекты возвращаются в том порядке, в котором они встречаются на сайте, и любой из примерно двадцати различных объектов может быть возвращен в любое время.
Работая через API, я не могу найти способ решить эту проблему с помощью Argonaut. Кажется, что все API-интерфейсы требуют параметризации типов, что сложно в среде, где невозможно предсказать тип следующего объекта. Одним из вариантов является отправка в разные кодеки на основе первых нескольких символов в каждом блоке JSON, но это подрывает цель отправки строки JSON парсеру и получения объекта взамен.
Лучшее, что мне удалось найти до сих пор, это чтобы все классы case верхнего уровня расширяли пустой trait
:
implicit def ModelDecodeJson: DecodeJson[Model] =
DecodeJson(c =>
c.as[ModelSubclassA].asInstanceOf[DecodeResult[Model]]
||| c.as[ModelSubclassB].asInstanceOf[DecodeResult[Model]]
// many more here!
)
К сожалению, ModelSubclassA
и ModelSubclassB
имеют несколько ассоциаций с другими классами case, и, хотя этот пример компилируется, во время выполнения происходит сбой при попытке анализа этих подтипов. Всего будет несколько десятков case-классов, формирующих иерархию возвращаемых данных.
Я также пытался построить это с пониманием for
, но и здесь не повезло.
Может ли кто-нибудь посоветовать лучшие образцы здесь?
ОБНОВЛЕНИЕ
Следующее выглядит более масштабируемым, но типы не взаимодействуют друг с другом:
implicit def ModelDecodeJson: DecodeJson[Model] =
DecodeJson(c =>
(c.as[ModelSubclassA] ||| c.as[ModelSubclassB]).asInstanceOf[DecodeResult[Model]]
)
Ошибка:(10, 17) несоответствие типов; найдено: argonaut.DecodeResult[ModelSubclassB] требуется: argonaut.DecodeResult[Product with Serializable with Model] Примечание: ModelSubclassB ‹: продукт с Serializable with Model, но класс DecodeResult является инвариантным в типе A. Вместо этого вы можете определить A как +A . (SLS 4.5) ||| c.as[ModelSubclassB]).asInstanceOf[DecodeResult[Model]] ^
Итак, я начал смотреть исходный код и понял, что определение DecodeResult
было изменено, чтобы включить +A
, как было предложено ошибкой в версии 6.2-M1. Обновление до этой версии, к сожалению, превратило все кодеки подкласса Model
в неоднозначные имплициты, что имеет смысл.
Фу...