Wiki
Clone wikisnakeyaml / Howto
- Step-by-step instructions for common tasks
- How to substitute object in YAML document with a custom object
- How to use YAML with Spring to load properties
- How to use SnakeYAML under OSGi
- How to avoid implicit types
- How to skip a JavaBean property
- How to configure scalar style or flow style for JavaBean properties
- How to parse JodaTime
- Create Long instead of Integer
- Scala support
- To be done
Step-by-step instructions for common tasks
How to substitute object in YAML document with a custom object
Sometimes you need to instantiate a different object then encoded in the YAML document. For instance for the test you may need to look at the 'ID' property and instead of creating the object from YAML definition fetch it from the database using the provided ID as the key. This is how the custom constructor may look like:
class SelectiveConstructor extends Constructor { public SelectiveConstructor() { // define a custom way to create a mapping node yamlClassConstructors.put(NodeId.mapping, new MyPersistentObjectConstruct()); } class MyPersistentObjectConstruct extends Constructor.ConstructMapping { @Override protected Object constructJavaBean2ndStep(MappingNode node, Object object) { Class type = node.getType(); if (type.equals(MyPersistentObject.class)) { // create a map Map map = constructMapping(node); String id = (String) map.get("id"); return new MyPersistentObject(id, 17); } else { // create JavaBean return super.constructJavaBean2ndStep(node, object); } } } }
This is the code:
public void testConstructor() throws IOException { Yaml yaml = new Yaml(new SelectiveConstructor()); List<?> data = (List<?>) yaml .load("- 1\n- 2\n- !!examples.MyPersistentObject {amount: 222, id: persistent}"); // System.out.println(data); assertEquals(3, data.size()); MyPersistentObject myObject = (MyPersistentObject) data.get(2); assertEquals(17, myObject.getAmount()); assertEquals("persistent", myObject.getId()); }
How to use YAML with Spring to load properties
The Spring framework doesn’t have a YAML-based PropertyPlaceholderConfigurer
to load nested properties from a YAML property file.
This is an example of how it can be solved.
How to use SnakeYAML under OSGi
Use CustomClassLoaderConstructor
How to avoid implicit types
By default SnakeYAML tries to create implicit types (Date, Number) when the scalar matches the corresponding regular expression. It is possible (see examples) to configure Resolver
public class CustomResolver extends Resolver { /* * do not resolve float and timestamp */ protected void addImplicitResolvers() { addImplicitResolver(Tag.BOOL, BOOL, "yYnNtTfFoO"); // addImplicitResolver(Tags.FLOAT, FLOAT, "-+0123456789."); addImplicitResolver(Tag.INT, INT, "-+0123456789"); addImplicitResolver(Tag.MERGE, MERGE, "<"); addImplicitResolver(Tag.NULL, NULL, "~nN\0"); addImplicitResolver(Tag.NULL, EMPTY, null); // addImplicitResolver(Tags.TIMESTAMP, TIMESTAMP, "0123456789"); addImplicitResolver(Tag.VALUE, VALUE, "="); } }
public void testResolverToLoad() { Yaml yaml = new Yaml(new Constructor(new LoaderOptions()), new Representer(), new DumperOptions(), new CustomResolver()); Map<Object, Object> map = (Map<Object, Object>) yaml.load("1.0: 2009-01-01"); assertEquals(1, map.size()); assertEquals("2009-01-01", map.get("1.0")); }
How to skip a JavaBean
property
Sometimes there is a need to avoid dumping some JavaBean
properties. The requirement may be dynamic, based on the value of the property. For instance empty collections or 'null' values should not be dumped (serialized).
This is an example how it can be implemented:
class PointRepresenter extends Representer { @Override protected NodeTuple representJavaBeanProperty(Object javaBean, Property property, Object propertyValue, Tag customTag) { if (javaBean instanceof Point && "location".equals(property.getName())) { return null; } else { return super.representJavaBeanProperty(javaBean, property, propertyValue, customTag); } } }
javaBean
- is the actual instance of the JavaBean
* property
- internal representation of the JavaBean
property
* propertyValue
- the actual value which holds the property (in this example it is not used)
Another way is to use the @Transient
annotation on the getter:
import java.beans.Transient; class MyBean { private int value; public MyBean(int value) { this.value = value; } @Transient public int getValue() { return value; } public void setValue(int value) { this.value = value; } }
How to configure scalar style or flow style for JavaBean
properties
During serialisation (dumping), it may be desired to affect scalar style of flow style of selected JavaBean
properties. This is
an example how to configure it.
if (property.getName().equals("description")) { // if description contains ':' use folded scalar style and // not single quoted scalar style if (bean.getDescription().indexOf(':') > 0) { ScalarNode n = (ScalarNode) standard.getValueNode(); return new NodeTuple(standard.getKeyNode(), new ScalarNode(n.getTag(), n.getValue(), n.getStartMark(), n.getEndMark(), '>')); } }
PropertyComparator
).
How to parse JodaTime
Since JodaTime
is no JavaBean
(because it does not have an empty constructor), it requires some extra treatment when parsing.
The example is here.
private class ConstructJodaTimestamp extends ConstructYamlTimestamp { public Object construct(Node node) { Date date = (Date) super.construct(node); return new DateTime(date, DateTimeZone.UTC); } }
JodaTime
instance is the JavaBean
property you can use the following:
Yaml y = new Yaml(new JodaPropertyConstructor());
class JodaPropertyConstructor extends Constructor { public JodaPropertyConstructor() { yamlClassConstructors.put(NodeId.scalar, new TimeStampConstruct()); } class TimeStampConstruct extends Constructor.ConstructScalar { @Override public Object construct(Node nnode) { if (nnode.getTag().equals("tag:yaml.org,2002:timestamp")) { Construct dateConstructor = yamlConstructors.get(Tag.TIMESTAMP); Date date = (Date) dateConstructor.construct(nnode); return new DateTime(date, DateTimeZone.UTC); } else { return super.construct(nnode); } } } }
Create Long instead of Integer
SnakeYAML creates java.lang.Integer
for !!int
.
When the value does not fit then it tries to create java.lang.Long
and java.math.BigInteger
.
It possible to configure a custom way to create numbers. See the example for !!timestamp
. Any implicit tag can be re-defined.
Scala support
Scala YAML parser examples using SnakeYAML
To be done
- JavaBeans
- JavaBeans to support SortedSet property when it is encoded as a sequence
- order of JavaBean properties
- Context for error reporting consumes a lot of resources
- Add examples to create scalars that match custom regular expression
- BeanAccess.FIELD (Allow direct field access bypassing setters and getters)
- Provide sequence support for loading java.util.Set
- JodaTime
- Add examples for dumping custom values for !!bool and !!null
- Provide example for skipping null and empty collections
- Enhancement for a pretty format that combines BLOCK and FLOW
- Don't dump read-only properties by default. DumperOptions gets a setting to include read-only JavaBean properties
- Add example to ignore unknown tags (2009-12-08)
- Introduce multi contructors (tag prefix). A family of tags may be processed by a single constructor (2009-11-25)
- Add Velocity example
- Extend Resolver to support custom implicit types
- Add possibility to define a custom Class Loader
- Deliver possibility to load immutable instances with no global tags. Reflection for constructor arguments is used to get the runtime classes (2009-08-04)
- Add a simple test for Java Generics (BirdTest). Unfortunately it shows that some JVM implementations do not recognise classes for JavaBean properties at runtime. It leads to unnecessary global tags. See Generics in the documentation for details (2009-07-13)
- issue 99 (on Google Code): binary tag without escaping line breaks
- JavaBean without empty constructor but encoded as mapping (BeanAccess.FIELD and private empty constructor)
Updated