2013-10-18 7 views

Antwort

21

SnakeYAML ist eine qualitativ hochwertige, aktiv YAML-Parser/Renderer für Java gehalten. Sie können es natürlich von Scala verwenden.

HelicalYAML bietet eine Scala-Wrapper für SnakeYAML, wenn Sie diese Bequemlichkeit wirklich wollen, aber ich kann die Qualität oder Langlebigkeit des Projekts nicht bestätigen.

Ich würde gerne eine Bibliothek sehen, die entweder JSON oder YAML (oder was auch immer - Pluggable) zu einem gemeinsamen AST analysieren und dann Scala-Objekte mit typeclasses zu konstruieren. Mehrere JSON-Bibliotheken funktionieren so (und können natürlich auch JSON für Objekte rendern, die dieselben Typklassen verwenden), aber ich kenne keine solche Möglichkeit für YAML.

+0

Das HelicalYAML wird im Moment nicht gepflegt (lt. Projektwebsite; letztes Commit war 2010) – fikovnik

+2

Für mich ist der Hauptnachteil der Verwendung von SnakeYAML, dass man nur veränderbare Klassen mit Java-Sammlung serialisieren kann, wenn man automatisch parsen möchte mit Reflexion. Das bringt mich dazu, 2 Klassen zu schreiben. Unveränderliche, die in Code und Beany-One verwendet wird, die @BeanProperties enthält und Java-Auflistungen mit einer Build-Methode verwendet, um einen unveränderlichen Companion zu erstellen. Habe ich etwas verpasst? Vielleicht gibt es einige Makro-basierte Metaprogrammierungslösungen, um mich von der Doppelcodierung zu befreien? –

4

Für alle anderen, die über diese Antwort läuft und sucht Hilfe und Beispiele, fand ich eine basic example, die snakeYAML Hope es hilft. Hier ist der 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) 
    } 
} 
20

Hier ist ein Beispiel für die Verwendung der Jackson YAML Datenbindung.

Zuerst, hier ist unser Beispieldokument:

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

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

diese Abhängigkeiten hinzufügen:

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" 
) 

Hier ist unsere äußerste Klasse (Voraussetzung ist ein Guava artige Überprüfung und löst eine Ausnahme aus, wenn das Feld nicht ist in der 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 
} 

Und hier ist das innere Objekt:

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") 
} 

Schließlich ist hier, wie es instanziiert:

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

Interessante Nutzung der Jackson-Bibliothek. –

+0

Ich habe 'jackson-dataformat-yaml' verwendet, um die Anwendungskonfiguration viele Monate lang zu verwalten. Fand es besser als SnakeYaml. –

+0

Danke für das Beispiel! Ich würde die Guava-Vorbedingungen ändern in: 'require (_colour! = Null," color kann nicht null sein "); val color = _colour' – r90t

2

So habe ich nicht genug Ruf zu kommentieren (41 atm), aber ich dachte, meine Erfahrung wert war zu erwähnen.

Nachdem ich diesen Thread gelesen hatte, entschied ich mich, den Jackson YAML Parser zu verwenden, weil ich keine Konstruktoren mit null Argumenten haben wollte und es viel lesbarer war. Was ich nicht erkannte, war, dass keine Unterstützung für die Vererbung (Zusammenführung) gibt, und es gibt begrenzte Unterstützung für Ankerreferenz (ist das nicht der ganze Punkt von YAML ??).

Merge erklärt here.

Anchor Referenz erläutert here. Während es scheint, dass eine komplexe Ankerreferenz unterstützt wird, konnte ich sie in einem einfachen Fall nicht ausführen.

16

Ein wenig spät, um die Partei, aber ich denke, dass dieses Verfahren in der meisten nahtlosen Art und Weise funktioniert.Diese Methode hat:

  1. Automatische Konvertierung zu scala Sammlungstypen
  2. Use-Case-Klassen
  3. Keine Notwendigkeit für Standardcode wie BeanProperty/JsonProperty
  4. Verwendet 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) 
+1

3 Jahre ist ein bisschen spät? –

+3

Scala ist zeitlos !!! :-) –

+2

3 Jahre in * nicht * zu spät für * dieses * Thema - vorausgesetzt es ist noch kein komplett gelöstes. Ich benutze die oben angegebenen Bibliotheken erfolgreich, laufe aber weiterhin auf bestimmte Fehler. – javadba

1

Nach meiner Erfahrung sind JSON-Bibliotheken für Scala ausgereifter und benutzerfreundlicher (keiner der YAML-Ansätze ist so überzeugend oder so ausgereift wie JSON-Äquivalente, wenn es um den Umgang mit Fallklassen oder das Schreiben von benutzerdefinierten Serialisierern und Deserialisierern geht).

Als solche bevorzuge ich es, von YAML zu JSON zu konvertieren und dann eine JSON-Bibliothek zu verwenden. dies könnte etwas verrückt klingen, aber es funktioniert wirklich gut, vorausgesetzt:

  • Sie sind nur mit YAML arbeiten, die
  • Der Weg ist nicht die Leistung eine Teilmenge von JSON (Use-Cases in meiner Erfahrung viel) ist kritisch (wie es in diesen Ansatz Overhead)

Der Ansatz, den ich von YAML zu JSON zur Umwandlung verwenden, nutzt Jackson:

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

val json = new ObjectMapper() 
     .writer(new DefaultPrettyPrinter().withoutSpacesInObjectEntries()) 
     .writeValueAsString(tree) 
+1

Was halten Sie von moultingyaml - sehen Sie meine Antwort – akauppi

4

stieß ich auf moultingyaml heute.

MoultingYAML ist ein Scala Wrapper für SnakeYAML basierend auf Spray-JSON.

Es sieht mir sehr vertraut, nachdem ich Jahre mit spray-json gearbeitet habe. Ich denke, es könnte @ Sihils Bedürfnis nach einer "überzeugenden" und "ausgereiften" Scala YAML-Bibliothek entsprechen.

+0

Moultingyaml scheint einzelne Fälle zu unterstützen, was ein * sehr * begrenzter Anwendungsbereich ist. Ich möchte Unterstützung für verschachtelte Karten und Listen. – javadba

+0

Moultingyaml nimmt das gleiche Abstraktionsniveau wie spray.json, und für spray.json kann man etwa 20-Zeilen-Mustervergleich durchführen, um das zu verarbeiten, was ich denke, dass Sie wollen. – akauppi