В случае, если это кому-нибудь поможет, я решил это, переопределив listFormat в CollectionFormats (который используется в DefaultJsonProtocol).
trait FlexibleCollectionFormats extends CollectionFormats {
implicit override def listFormat[T: JsonFormat] = new RootJsonFormat[List[T]] {
import spray.json._
def write(list: List[T]) = JsArray(list.map(_.toJson).toVector)
def read(value: JsValue): List[T] = value match {
case JsArray(elements) => elements.map(_.convertTo[T])(collection.breakOut)
case JsString(element) => List[T](new JsString(element).convertTo[T])
case x => deserializationError("Expected List as JsArray, but got " + x)
}
}
}
Затем я создал собственный протокол вместо DefaultJsonProtocol, который в основном использует те же, что и Default, но переопределяет CollectionFormats:
trait FlexibleDefaultJsonProtocol
extends BasicFormats
with StandardFormats
// with CollectionFormats
with FlexibleCollectionFormats
with ProductFormats
with AdditionalFormats
object FlexibleDefaultJsonProtocol extends FlexibleDefaultJsonProtocol
и позже вы используете extends FlexibleDefaultJsonProtocol
вместоDefaultJsonProtocol.Вы всегда можете переключаться и использовать один или другой в своих классах, поэтому мне нравится гибкий подход, который он предоставляет.