2016-04-05 5 views
0

В Скале, У меня есть следующие черты и классы определены (имена, используемые только для целей иллюстрации):Scala - игра JSON черта сериализации

trait Entity { 
    def x() : Collection 
} 

case class X(x : Int, y : Int) extends Entity { 
    def x() : Collection = XCollection() 
} 

case class Y(x : Int, y : Int) extends Entity { 
    def x() : Collection = YCollection() 
} 

В то время как экземпляры класса создаются путем анализа ответа от веб-службы REST API.

Несмотря на то, что подход, использующий библиотеку play-json, работает в случае разбора ответа и возвращает представление класса ответа, я боролся со следующим: наличие универсальной функции, принимающей параметр типа, тогда как T : Entity, и возвращает экземпляр типа T.

для примера рассмотрим следующее:

def parse[T <: Entity](json : String) : Option[T] = Json.parse(json).asOpt[T](Variants.format[T]) 

Учитывая тип T, я хотел бы разобрать строку JSON и произвести экземпляр типа T, тогда как экземпляр является производным от объекта Entity. Тем не менее, я продолжаю получать ошибку компиляции в отношении API отражения:

Error:(25, 96) exception during macro expansion: 
scala.ScalaReflectionException: type T is not a class 
at scala.reflect.api.Symbols$SymbolApi$class.asClass(Symbols.scala:323) 
at scala.reflect.internal.Symbols$SymbolContextApiImpl.asClass(Symbols.scala:73) 
at julienrf.variants.Variants$Impl$.baseAndVariants(Variants.scala:132) 
at julienrf.variants.Variants$Impl$.formatDiscriminator(Variants.scala:99) 
at julienrf.variants.Variants$Impl$.format(Variants.scala:94) 
def parse[T <: Entity](json : String) : Option[T] =  Json.parse(json).asOpt[T](Variants.format[T]) 
                         ^

Поэтому я был бы признателен за помощь!

Благодаря

ответ

2

Лучше позволить implicits решить ваши требования к формату, чем использовать какой-то фабрики:

def parse[T <: Entity](json: String)(implicit r: Reads[T]): Option[T] = 
    Json.parse(json).asOpt[T] 

Тогда, если у вас есть формат в текущем контексте неявно определено, parse будет работать:

implicit val XFormat = Json.format[X] 

parse[X](Json.stringify(Json.toJson(X(1, 2))) // returns X(1, 2) 

Update

Вы можете сделать это как завод, если вы действительно этого хотите. Я бы поставил под сомнение, стоит ли это делать, но теоретически я мог бы представить некоторые отдельные ситуации, когда вы не хотели бы использовать неявную механику. Тем не менее, я думаю, что если implicits не работает для вас, вы можете иметь проблемы архитектуры в коде

import play.api.libs.json.{Json, Reads} 

    import scala.reflect.runtime.universe._ 

    trait Entity 
    case class X(x : Int, y : Int) extends Entity 
    case class Y(x : Int, y : Int) extends Entity 


    val mapping = Map[Type, Reads[_]](typeOf[X] -> Json.format[X], typeOf[Y] -> Json.format[Y]) 
    def getFormat[T](tpe: Type): Reads[T] = 
    mapping(tpe).asInstanceOf[Reads[T]] 

    def parse[T : TypeTag](json: String): Option[T] = { 
    val map = mapping(implicitly[TypeTag[T]].tpe) 
    Json.parse(json).asOpt[T](getFormat(implicitly[TypeTag[T]].tpe)) 
    } 

    println(parse[X]("""{"x": 5, "y": 6}""")) 
    println(parse[Y]("""{"x": 5, "y": 6}""")) 
+0

Хотя проблема действительно, есть еще одна точка слева: каждый раз, когда вам нужно разобрать экземпляр типа Entity , то есть либо X, либо Y-экземпляры, вам необходимо явно указать формат или читать, что именно то, чего я пытался избежать. Скорее, я ищу следующее: parse [X] (jsonString), тогда как сериализатор должен быть определен в функции синтаксического анализа. – dsafa

+0

@dsafa См. Обновление. – Archeg

+0

@dsafa И обратите внимание, что вам не нужно явно указывать формат. В первом примере формат предоставляется неявно, поэтому ключевое слово – Archeg

Смежные вопросы