web-dev-qa-db-fra.com

Travailler avec YAML pour Scala

J'ai trouvé une bibliothèque pour cela https://github.com/daltontf/scala-yaml , mais il semble que peu de développeurs l'utilisent et c'est assez obsolète. Il se peut aussi que ce soit http://www.lag.net/configgy/ si le lien n'était pas mort.

Je me demande quelle est la bibliothèque la plus populaire ou de facto pour travailler avec YAML dans Scala?

28
アレックス

SnakeYAML est un analyseur/rendu YAML de haute qualité et activement maintenu pour Java. Vous pouvez bien sûr l'utiliser depuis Scala.

HelicalYAML fournit un wrapper Scala pour SnakeYAML si vous voulez vraiment cette commodité, mais je ne peux pas attester de la qualité ou de la longévité du projet.

Je serais ravi de voir une bibliothèque qui pourrait analyser JSON ou YAML (ou quoi que ce soit - enfichable) à un AST puis construire des objets Scala utilisant des classes de type) Plusieurs bibliothèques JSON fonctionnent comme ça (et bien sûr peuvent également rendre JSON pour des objets utilisant les mêmes classes de types), mais je ne connais pas une telle facilité pour YAML.

21
AmigoNico

Voici un exemple d'utilisation de la liaison de données Jackson YAML .

Tout d'abord, voici notre exemple de document:

name: test
parameters:
  "VERSION": 0.0.1-SNAPSHOT

things:
  - colour: green 
    priority: 128
  - colour: red
    priority: 64

Ajoutez ces dépendances:

libraryDependencies ++= Seq(
  "com.fasterxml.jackson.core" % "jackson-core" % "2.1.1",
  "com.fasterxml.jackson.core" % "jackson-annotations" % "2.1.1",
  "com.fasterxml.jackson.core" % "jackson-databind" % "2.1.1",
  "com.fasterxml.jackson.dataformat" % "jackson-dataformat-yaml" % "2.1.1"
)

Voici notre classe la plus externe (les conditions préalables sont une vérification de type goyave et déclenchent une exception si ledit champ n'est pas dans le YAML):

import Java.util.{List => JList, Map => JMap}
import collection.JavaConversions._
import com.fasterxml.jackson.annotation.JsonProperty

class Sample(@JsonProperty("name") _name: String,
             @JsonProperty("parameters") _parameters: JMap[String, String],
             @JsonProperty("things") _things: JList[Thing]) {
  val name = Preconditions.checkNotNull(_name, "name cannot be null")
  val parameters: Map[String, String] = Preconditions.checkNotNull(_parameters, "parameters cannot be null").toMap
  val things: List[Thing] = Preconditions.checkNotNull(_things, "things cannot be null").toList
}

Et voici l'objet intérieur:

import com.fasterxml.jackson.annotation.JsonProperty

class Thing(@JsonProperty("colour") _colour: String,
            @JsonProperty("priority") _priority: Int {
  val colour = Preconditions.checkNotNull(_colour, "colour cannot be null")
  val priority = Preconditions.checkNotNull(_priority, "priority cannot be null")
}

Enfin, voici comment l'instancier:

 val reader = new FileReader("sample.yaml")
 val mapper = new ObjectMapper(new YAMLFactory())
 val config: Sample = mapper.readValue(reader, classOf[Sample])
24
Greg Kopff

Un peu tard pour la fête mais je pense que cette méthode fonctionne de la manière la plus transparente. Cette méthode a:

  1. Conversion automatique en types de collection scala
  2. Classes de cas d'utilisation
  3. Pas besoin de code passe-partout comme BeanProperty/JsonProperty
  4. Utilise Jackson-YAML & Jackson-scala

Code:

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import com.fasterxml.jackson.module.scala.DefaultScalaModule

case class Prop(url: List[String])

// uses Jackson YAML to parsing, relies on SnakeYAML for low level handling
val mapper: ObjectMapper = new ObjectMapper(new YAMLFactory())

// provides all of the Scala goodiness
mapper.registerModule(DefaultScalaModule)
val prop: Prop = mapper.readValue("url: [abc, def]", classOf[Prop])

// prints List(abc, def)
println(prop.url)
21
Gaurav Kumar

Je suis tombé sur moultingyaml aujourd'hui.

MoultingYAML est un wrapper Scala pour SnakeYAML basé sur spray-json.

Cela me semble assez familier, après avoir travaillé des années avec spray-json. Je pense que cela pourrait correspondre au besoin de @ sihil d'une bibliothèque "convaincante" et "mature" Scala YAML.

5
akauppi

Et maintenant, nous avons circe-yamlhttps://github.com/circe/circe-yaml

SnakeYAML fournit une Java API pour analyser YAML et rassembler ses structures en classes JVM. Cependant, vous trouverez peut-être le moyen de circe de rassembler en un Scala ADT préférable - en utilisant la spécification ou la dérivation au moment de la compilation plutôt que la réflexion à l'exécution. Cela vous permet d'analyser YAML dans Json et d'utiliser vos décodeurs existants (ou génériques de circe) pour effectuer le triage ADT. Vous pouvez également utiliser l'encodeur de circe pour obtenir un Json, et l'imprimer sur YAML en utilisant cette bibliothèque.

5
SemanticBeeng

Pour toute autre personne qui traverse cette réponse et cherche de l'aide et des exemples, j'ai trouvé un exemple de base qui utilise snakeYAML J'espère que cela aide. Voici le code:

package yaml

import org.yaml.snakeyaml.Yaml
import org.yaml.snakeyaml.constructor.Constructor
import scala.collection.mutable.ListBuffer
import scala.reflect.BeanProperty

object YamlBeanTest1 {

  val text = """
  accountName: Ymail Account
  username: USERNAME
  password: PASSWORD
  mailbox: INBOX
  imapServerUrl: imap.mail.yahoo.com
  protocol: imaps
  minutesBetweenChecks: 1
  usersOfInterest: [barney, betty, wilma]
  """

  def main(args: Array[String]) {
    val yaml = new Yaml(new Constructor(classOf[EmailAccount]))
    val e = yaml.load(text).asInstanceOf[EmailAccount]
    println(e)
  }

}

/**
 * With the Snakeyaml Constructor approach shown in the main method,
 * this class must have a no-args constructor.
 */
class EmailAccount {
  @BeanProperty var accountName: String = null
  @BeanProperty var username: String = null
  @BeanProperty var password: String = null
  @BeanProperty var mailbox: String = null
  @BeanProperty var imapServerUrl: String = null
  @BeanProperty var minutesBetweenChecks: Int = 0
  @BeanProperty var protocol: String = null
  @BeanProperty var usersOfInterest = new Java.util.ArrayList[String]()

  override def toString: String = {
    return format("acct (%s), user (%s), url (%s)", accountName, username, imapServerUrl)
  }
}
4
Peter Klipfel

Je n'ai donc pas assez de réputation pour commenter (41 atm) mais j'ai pensé que mon expérience méritait d'être mentionnée.

Après avoir lu ce fil, j'ai décidé d'essayer d'utiliser l'analyseur Jackson YAML parce que je ne voulais pas de constructeurs à zéro argument et qu'il était beaucoup plus lisible. Ce que je ne savais pas, c'est que il n'y a pas de support pour l'héritage (fusion), et il y a un support limité pour la référence d'ancrage (n'est-ce pas que le point entier de YAML ??).

La fusion est expliquée ici .

La référence d'ancrage est expliquée ici . Bien qu'il semble qu'une référence d'ancrage complexe soit prise en charge, je n'ai pas pu la faire fonctionner dans un cas simple.

4
Daniel Fithian

D'après mon expérience, les bibliothèques JSON pour Scala sont plus matures et plus faciles à utiliser (aucune des approches YAML n'est extrêmement convaincante ou aussi mature que les équivalents JSON lorsqu'il s'agit de traiter des classes de cas ou d'écrire des serialiseurs personnalisés). et désérialiseurs).

En tant que tel, je préfère convertir de YAML en JSON, puis utiliser une bibliothèque JSON. cela peut sembler un peu fou mais ça marche vraiment bien à condition que:

  • Vous travaillez uniquement avec YAML qui est un sous-ensemble de JSON (beaucoup de cas d'utilisation d'après mon expérience)
  • Le chemin n'est pas critique en termes de performances (car il y a des frais généraux dans l'adoption de cette approche)

L'approche que j'utilise pour convertir de YAML en JSON s'appuie sur Jackson:

val tree = new ObjectMapper(new YAMLFactory()).readTree(yamlTemplate)

val json = new ObjectMapper()
        .writer(new DefaultPrettyPrinter().withoutSpacesInObjectEntries())
        .writeValueAsString(tree)
2
sihil