34

I found one library for this https://github.com/daltontf/scala-yaml, but it seems like not many developers use it and it's pretty outdated. It also might be this http://www.lag.net/configgy/ if the link wasn't dead.

I wonder, what is the most popular or de-facto library for working with YAML in Scala?

8 Answers 8

28

Here's an example of using the Jackson YAML databinding.

First, here's our sample document:

name: test parameters: "VERSION": 0.0.1-SNAPSHOT things: - colour: green priority: 128 - colour: red priority: 64 

Add these dependencies:

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

Here's our outermost class (Preconditions is a Guava-like check and raises an exception if said field is not in the 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 } 

And here's the inner object:

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

Finally, here's how to instantiate it:

 val reader = new FileReader("sample.yaml") val mapper = new ObjectMapper(new YAMLFactory()) val config: Sample = mapper.readValue(reader, classOf[Sample]) 
Sign up to request clarification or add additional context in comments.

3 Comments

I've been using 'jackson-dataformat-yaml' for maintaining application config many months now. Found it better than SnakeYaml.
Thank you for the example! I would change Guava preconditions to: require(_colour != null, "colour cannot be null"); val colour = _colour
Thanks for the tip @r90t - I wrote this a while ago and it was my first foray into Scala.
25

SnakeYAML is a high-quality, actively maintained YAML parser/renderer for Java. You can of course use it from Scala.

If you're already working with circe, you might be interested in circe-yaml which uses SnakeYAML to parse a YAML file and then converts the result to a circe AST.

I would love to see a library that could parse either JSON or YAML (or whatever -- pluggable) to a common AST and then construct Scala objects using typeclasses. Several JSON libraries work like that (and of course can also render JSON for objects using the same typeclasses), but I don't know of such a facility for YAML.


PS: There also appear to be a number of seemingly abandoned wrappers for SnakeYAML, namely HelicalYAML and yaml4s

3 Comments

The HelicalYAML is not maintained at the moment (according to the project website; latest commit was in 2010)
For me the main disadvantage of using SnakeYAML is that you can only serialize mutable class with java collection if you want auto-parsing using reflection. That makes me to write 2 classes. Immutable one to use in code and beany-one that has @BeanProperties and uses java collections with build method on it to construct immutable companion. Did I miss something? Maybe there are some macros-based meta programming solutions to free me from double-coding?
circe-yaml was mentioned below by @SemanticBeeng. It translates SnakeYAML's AST into circe's AST and enables parsing YAML 1.1 documents into circe's Json AST.
25

A little late to the party but I think this method works in the most seamless way. This method has:

  1. Automatic conversion to scala collection types
  2. Use case classes
  3. No need for boilerplate code like BeanProperty/JsonProperty
  4. Uses 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 Comment

3 years in not late for this topic - given it is still not a completely solved one. I am using the given libraries above successfully but continue to run into specific gotchas.
11

And now we have circe-yaml https://github.com/circe/circe-yaml

SnakeYAML provides a Java API for parsing YAML and marshalling its structures into JVM classes. However, you might find circe's way of marshalling into a Scala ADT preferable -- using compile-time specification or derivation rather than runtime reflection. This enables you to parse YAML into Json, and use your existing (or circe's generic) Decoders to perform the ADT marshalling. You can also use circe's Encoder to obtain a Json, and print that to YAML using this library.

Comments

6

I came across moultingyaml today.

MoultingYAML is a Scala wrapper for SnakeYAML based on spray-json.

It looks quite familiar to me, having worked years with spray-json. I think it might fit @sihil's need of a "compelling" and "mature" Scala YAML library.

3 Comments

Moultingyaml seems to support single case clases which is a very limited scope. I want support for nested maps and lists.
Moultingyaml takes the same abstraction level as spray.json, and for spray.json one can do about 20-line pattern match to handle what I think you want.
@akauppi.. Could you please suggest your inputs on this question as well.. stackoverflow.com/questions/63188174/…
4

For anyone else that runs across this answer and is looking for help and examples, I found a basic example that uses snakeYAML Hope it helps. Here's the 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) } } 

Comments

4

So I don't have enough reputation to comment (41 atm) but I thought my experience was worth mentioning.

After reading this thread, I decided to try to use the Jackson YAML parser because I didn't want zero-argument constructors and it was much more readable. What I didn't realize was that there is no support for inheritance (merging), and there is limited support for anchor reference (isn't that the whole point of YAML??).

Merge is explained here.

Anchor reference is explained here. While it appears that complex anchor reference is supported, I could not get it to work in a simple case.

Comments

3

In my experience JSON libraries for Scala are more mature and easier to use (none of the YAML approaches are enormously compelling or as mature as JSON equivalents when it comes to dealing with case classes or writing custom serialisers and deserialisers).

As such I prefer to converting from YAML to JSON and then use a JSON library. this might sound slightly crazy but it works really well provided that:

  • You are only working with YAML that is a subset of JSON (a great deal of use cases in my experience)
  • The path is not performance critical (as there is overhead in taking this approach)

The approach I use for converting from YAML to JSON leverages Jackson:

val tree = new ObjectMapper(new YAMLFactory()).readTree(yamlTemplate) val json = new ObjectMapper() .writer(new DefaultPrettyPrinter().withoutSpacesInObjectEntries()) .writeValueAsString(tree) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.