2017-10-19 19 views
1

J'ai un client HTTP écrit en Scala qui utilise json4s/jackson pour sérialiser et désérialiser les charges utiles HTTP. Pour l'instant, je n'utilisais que des classes de cas Scala comme modèle et tout fonctionnait bien, mais maintenant je dois communiquer avec un service tiers. Ils m'ont fourni leur propre modèle, mais il est écrit en Java, alors maintenant je dois désérialiser jsons aussi aux classes Java. Il semble fonctionner correctement avec les classes simples, mais quand la classe contient des collections comme des listes ou des cartes json4s a des problèmes et définit tous ces champs à null.Désérialisation d'objets Java avec Scala et json4s

Y a-t-il un moyen de gérer de tels cas? Peut-être que je devrais utiliser différents formats (j'utilise DefaultFormats + quelques uns personnalisés). Exemple de problème avec le test:

import org.json4s.DefaultFormats 
import org.json4s.jackson.Serialization.read 
import org.scalatest.{FlatSpec, Matchers} 

class JavaListTest extends FlatSpec with Matchers{ 

    implicit val formats = DefaultFormats 

    "Java List" should "be deserialized properly" in { 
     val input = """{"list":["a", "b", "c"]}""" 
     val output = read[ObjectWithList](input) 
     output.list.size() shouldBe 3 
    } 
} 

Et un exemple de classe Java:

import java.util.List; 

public class ObjectWithList { 
    List<String> list; 
} 

J'ai aussi remarqué que quand je vais essayer de désérialiser à Scala classe affaire qui contient java.util.List[String] type de champ que je vais obtenir une exception de type: org.json4s.package$MappingException: Expected collection but got List[String]

Répondre

1

La clé pour résoudre votre problème est la composition des formateurs. Fondamentalement, vous voulez définir le formateur JList comme formateur de liste composé avec la fonction toJList. Malheureusement, json4s Les formateurs sont extrêmement difficiles à composer, j'ai donc utilisé les Reader s pour vous faire une idée. J'ai aussi simplifié un exemple, d'avoir seulement la liste java:

import DefaultReaders._ 
import scala.collection.JavaConverters._ 

implicit def javaListReader[A: Reader]: Reader[java.util.List[A]] = new Reader[util.List[A]] { 
     override def read(value: JValue) = DefaultReaders.traversableReader[List, A].read(value).asJava 
} 

val input = """["a", "b", "c"]""" 
val output = Formats.read[java.util.List[String]](parse(input)) 

A ma connaissance json4s lecteurs ne fonctionnent pas avec les classes Java de la boîte, de sorte que vous pouvez soit nécessaire de mettre en œuvre le Serializer[JList[_]] de la même manière, ou un miroir vos classes Java avec des classes de cas et utilisez-les dans votre domaine.

P.S. Vous recommande fortement de passer à circe ou argonaut, alors vous oublierez le plus de problèmes avec jsons.

+1

Pour être honnête, j'ai essayé d'utiliser circe (que j'avais précédemment remplacé par json4s en raison d'un long problème de compilation) mais je trouve cela trop difficile à comprendre sur mon niveau d'expertise dans Scala. J'ai utilisé des décodeurs de 'io.circe.generic.auto._' mais il semble que ceux-ci n'incluent pas les décodeurs Java. Savez-vous s'il y a des décodeurs pour les classes java à circe ou si je devrais mettre en place mes propres décodeurs personnalisés si je décide de revenir à circe? –

+1

comme je le sais 'generic.auto._' utilise la conversion en' HList' et 'Coproduct' de shapeless, ce qui ne fonctionne pas pour les classes Java. J'ai peur que vous ayez besoin d'implémenter vos propres décodeurs pour les classes Java à circe. –