2017-10-19 67 views
6

następujący test fragmencieJSON4S wskazówka nie działa

implicit val formats = DefaultFormats + FullTypeHints(Contacts.classList) 

val serialized = Serialization.write(List(Mail(field = "[email protected]", note = "Random note."))) 
println(serialized) 

Serialization.read[List[Contact[_]]](serialized).isInstanceOf[List[Mail]] should be (true) 

zawodzi z

Can't find constructor for Contact[Object] 
org.json4s.package$MappingException: Can't find constructor for Contact[Object] 
    at org.json4s.reflect.package$.fail(package.scala:95) 
    at org.json4s.reflect.ScalaSigReader$$anonfun$5.apply(ScalaSigReader.scala:21) 
    at org.json4s.reflect.ScalaSigReader$$anonfun$5.apply(ScalaSigReader.scala:21) 
    at scala.Option.getOrElse(Option.scala:121) 
    at org.json4s.reflect.ScalaSigReader$.readConstructor(ScalaSigReader.scala:21) 
    at org.json4s.reflect.Reflector$ClassDescriptorBuilder.ctorParamType(Reflector.scala:93) 
    at org.json4s.reflect.Reflector$ClassDescriptorBuilder$$anonfun$createConstructorDescriptors$3$$anonfun$15.apply(Reflector.scala:156) 
    at org.json4s.reflect.Reflector$ClassDescriptorBuilder$$anonfun$createConstructorDescriptors$3$$anonfun$15.apply(Reflector.scala:142) 
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234) 
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234) 
    at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59) 
    at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48) 
    at scala.collection.TraversableLike$class.map(TraversableLike.scala:234) 
    at scala.collection.AbstractTraversable.map(Traversable.scala:104) 
    at org.json4s.reflect.Reflector$ClassDescriptorBuilder$$anonfun$createConstructorDescriptors$3.apply(Reflector.scala:142) 
    at org.json4s.reflect.Reflector$ClassDescriptorBuilder$$anonfun$createConstructorDescriptors$3.apply(Reflector.scala:136) 
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234) 
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234) 
    at scala.collection.mutable.ArraySeq.foreach(ArraySeq.scala:74) 
    at scala.collection.TraversableLike$class.map(TraversableLike.scala:234) 
    at scala.collection.AbstractTraversable.map(Traversable.scala:104) 
    at org.json4s.reflect.Reflector$ClassDescriptorBuilder.createConstructorDescriptors(Reflector.scala:136) 
    at org.json4s.reflect.Reflector$ClassDescriptorBuilder.constructorsAndCompanion(Reflector.scala:121) 
    at org.json4s.reflect.Reflector$ClassDescriptorBuilder.result(Reflector.scala:183) 
    at org.json4s.reflect.Reflector$.createDescriptor(Reflector.scala:53) 
    at org.json4s.reflect.Reflector$$anonfun$describe$1.apply(Reflector.scala:48) 
    at org.json4s.reflect.Reflector$$anonfun$describe$1.apply(Reflector.scala:48) 
    at org.json4s.reflect.package$Memo.apply(package.scala:36) 
    at org.json4s.reflect.Reflector$.describe(Reflector.scala:48) 
    at org.json4s.Extraction$$anonfun$extract$6.apply(Extraction.scala:393) 
    at org.json4s.Extraction$$anonfun$extract$6.apply(Extraction.scala:392) 
    at org.json4s.Extraction$.customOrElse(Extraction.scala:606) 
    at org.json4s.Extraction$.extract(Extraction.scala:392) 
    at org.json4s.Extraction$CollectionBuilder$$anonfun$7.apply(Extraction.scala:410) 
    at org.json4s.Extraction$CollectionBuilder$$anonfun$7.apply(Extraction.scala:410) 
    at scala.collection.immutable.List.map(List.scala:284) 
    at org.json4s.Extraction$CollectionBuilder.mkCollection(Extraction.scala:410) 
    at org.json4s.Extraction$CollectionBuilder.result(Extraction.scala:430) 
    at org.json4s.Extraction$$anonfun$extract$5.apply(Extraction.scala:382) 
    at org.json4s.Extraction$$anonfun$extract$5.apply(Extraction.scala:382) 
    at org.json4s.Extraction$.customOrElse(Extraction.scala:606) 
    at org.json4s.Extraction$.extract(Extraction.scala:382) 
    at org.json4s.Extraction$.extract(Extraction.scala:39) 
    at org.json4s.ExtractableJsonAstNode.extract(ExtractableJsonAstNode.scala:21) 
    at org.json4s.jackson.Serialization$.read(Serialization.scala:50) 
    at org.json4s.Serialization$class.read(Serialization.scala:30) 
    at org.json4s.jackson.Serialization$.read(Serialization.scala:17) 

gdzie Contact jest

abstract class Contact[Field : Validable](
    val field: Field, 
    val created: Long, 
    val updated: Long, 
    val note: String) { } 

i Mail jest

case class Mail(
    override val field: String, 
    override val created: Long = System.currentTimeMillis(), 
    override val updated: Long = System.currentTimeMillis(), 
    override val note: String) 
extends Contact[String](field, created, updated, note)(Mail) 

case object Mail extends Validable[String] { 
    override def valid(field: String): Boolean = { 
    Validator.email(field) 
    } 
} 

i wyjście test jest

[{"jsonClass":"whatever.core.entities.utility.contact.Mail","field":"[email protected]","created":1508428385266,"updated":1508428385266,"note":"Random note."}] 

kopanie w CODEBASE JSON4S wskazówka pokazuje, że typ nie jest w ogóle używany.

Jak mogę zmusić JSON4S do korzystania z podpowiedzi typu?

Cheers

Odpowiedz

0

Wdrożenie Contact pomocą trait S i będzie działać.

+0

Nie musisz (nawet jeśli to rzeczywiście działa), spójrz na moją odpowiedź, aby poznać również przyczynę. –

0

Jest to przykład tego, jak można użyć FullTypeHints.

Nie można pytać niejawnie o numer Validable[Field], ani dodawać wielu jawnych list argumentów (i dzieje się tak również dla niejawnie parametrów, patrz uwaga poniżej), ponieważ nie są one obsługiwane przez JSON4S.

Uwaga: pytanie o Validable[Field] bezwarunkowo z Contact[Field: Validable] jest równoznaczne z dodaniem dodatkowej listy argumentów z implicit validable: Validable[Field].

Możesz, zamiast dodać dodatkowy parametr do konstruktora validable: Validable[Field]Contact lub (jak w poniższym przykładzie) a validable pola, które powinny zostać zastąpione przez konkretnych klas (jak Mail) rozszerzających Contact klasy abstrakcyjnej.

trait Validable[T]{ 
    def valid(field: T): Boolean 
} 

abstract class Contact[Field](
    val field: Field, val created: Long, 
    val updated: Long, val note: String) { 
    val validable: Validable[Field] 
} 

object Contacts{ val classList = List(classOf[Mail]) } 

case class Mail(
    override val field: String, 
    override val created: Long = System.currentTimeMillis(), 
    override val updated: Long = System.currentTimeMillis(), 
    override val note: String 
) extends Contact[String](field, created, updated, note){ 
    override val validable: Validable[String] = Mail 
} 

case object Mail extends Validable[String] { 
    override def valid(field: String): Boolean = true 
} 

implicit val formats = DefaultFormats + FullTypeHints(Contacts.classList) 
val mail: List[Mail] = List(Mail(field = "[email protected]", note = "Random note.")) 
val serialized = Serialization.write(mail) 
val mailS = Serialization.read[List[Contact[_]]](serialized) 

print(mail == mailS) 

serialized JSON reprezentacja jest następujący:

[ 
    { 
    "jsonClass":"whatever.core.entities.utility.contact$Mail", 
    "field":"[email protected]", 
    "created":1509098018776, 
    "updated":1509098018776, 
    "note":"Random note." 
    } 
] 
+0

Czy to ten sam kod do mojego? – Dyin

+0

Przepraszam, brakowało mi "Validable [Field]", zaktualizowałem moją odpowiedź, aby sobie z tym poradzić. Teraz powinien w pełni odpowiedzieć na twoje pytanie. –

+0

Dzięki, ale to nie zadziała, ponieważ 'Contact [Field]' jest klasą abstrakcyjną. 'Kontakt [Pole]' musi być cechą. – Dyin