Yaml BUILDER to simmplify custom types

214 views
Skip to first unread message

franco graziosi

unread,
Feb 21, 2012, 4:35:01 AM2/21/12
to SnakeYAML
Hi,

To simplify handling of custom types I have created a YambBuilder,
whose code I
am pasting at bottom. Here is, for example, how to use it to read
numeric
values, including optional percent sign ad double instead of float:

YamlBuilder builder = new YamlBuilder();
builder.addHelper(new YamlBuilder.BaseHelper(Double.class, "!
Double",
"^ *(-?[0-9]+(\\.[0-9]*)?)(%?) *$", "-123456789") {
public Object construct(Node node, String[] groups) {
double value = Double.parseDouble(groups[1]);
if ("%".equals(groups[3]))
value = value / 100.0;
return value;
}
});
yaml = builder.buildYaml();

And here is how it can be used with the [dice example](http://
www.google.com/url?sa=D&q=http://code.google.com/p/snakeyaml/wiki/Documentation%23Constructors,_representers,_resolvers&usg=AFQjCNFU-tzdF7IvTFiXHpd0BudH-liFBA):

YamlBuilder builder = new YamlBuilder();
builder.addHelper(new YamlBuilder.BaseHelper(Double.class, "!
Double",
"(\\d+)d(\\d+)"", "1234567890") {
public Object construct(Node node, String[] groups) {
return new Dice(Integer.parseInt(groups[1]),
Integer.parseInt(groups[2]));
}
});
yaml = builder.buildYaml();

Here is its source for anybode who wish to use it:

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.AbstractConstruct;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.nodes.ScalarNode;
import org.yaml.snakeyaml.nodes.Tag;
import org.yaml.snakeyaml.representer.Represent;
import org.yaml.snakeyaml.representer.Representer;

public class YamlBuilder {
private List<Helper> helpers = new ArrayList<Helper>();
private Constructor constructor;

public void addHelper(Helper helper) {
helpers.add(helper);
}

public Yaml buildYaml() {
Yaml result = new Yaml(constructor = new MyConstructor(), new
MyRepresenter());
for (Helper helper : helpers) {
if (helper.getPattern() != null)
result.addImplicitResolver(new Tag(helper.getTag()),
helper.getPattern(),
helper.getFirstCharacterSet());
}
return result;
}

public Constructor getConstructor() {
return constructor;
}

/**
* A Helper is responsible for converting between instanced of
its type and Yaml.
* @param <E> The type to be converted.
*/
public interface Helper<E> {

/**
* @return The type itself.
*/
public Class<? extends E> getType();

/**
* Shall convert type instance to a node.
*/
public Node representData(E data);

/**
* Shall convert a node to a type instance.
* @param groups If a regular expression has been used to
recognize the
* type, this array contains the groups of the regular
expression,
* otherwise it is null.
*/
public E construct(Node node, String[] groups);

/**
* Shall return the tag used to recognize the type
*/
public String getTag();

/**
* @return The pattern (if any) used to recognize an instance
of this type
* (used to add an implicit resolver)
*/
public Pattern getPattern();

/**
* @return The set of first characters used to add an implicit
resolver.
*/
public String getFirstCharacterSet();
}

class MyRepresenter extends Representer {

public MyRepresenter() {
for (Helper helper : helpers)
representers.put(helper.getType(), new
RepresentType(helper));
}
}

class RepresentType implements Represent {

private Helper helper;

public RepresentType(Helper helper) {
this.helper = helper;
}

@Override
public Node representData(Object o) {
return helper.representData(o);
}
}

class MyConstructor extends Constructor {

public MyConstructor() {
for (Helper helper : helpers) {
yamlConstructors.put(new Tag(helper.getTag()), new
ConstructType(helper));
}
}

class ConstructType extends AbstractConstruct {

private Helper helper;

public ConstructType(Helper helper) {
this.helper = helper;
}


@Override
public Object construct(Node node) {
String[] groups = null;
String value = ((ScalarNode) node).getValue();
if (helper.getPattern() != null) {
Matcher m = helper.getPattern().matcher(value);
if (m.matches()) {
groups = new String[m.groupCount() + 1];
for (int i = 0; i <= m.groupCount(); i++)
groups[i] = m.group(i);
}
}
return helper.construct(node, groups);
}
}
}

public static abstract class BaseHelper implements Helper {

private Class<?> type;
private String tag;
private Pattern pattern;
private String firstCharacterSet;

public BaseHelper(Class<?> type) {
this(type, null);
}

public BaseHelper(Class<?> type, String tag) {
this(type, tag, null, null);
}

public BaseHelper(Class<?> type, String tag, String regex,
String firstCharacterSet) {
this.type = type;
this.tag = tag;
pattern = regex == null ? null : Pattern.compile(regex);
this.firstCharacterSet = firstCharacterSet;
}

@Override
public Class getType() {
return type;
}

@Override
public String getTag() {
return tag == null ? type.getName() : tag;
}

@Override
public String getFirstCharacterSet() {
return firstCharacterSet;
}

@Override
public Pattern getPattern() {
return pattern;
}

@Override
public Node representData(Object data) {
Node result = new ScalarNode(new Tag(getTag()),
data.toString(), null,
null, null);
return result;
}
}
}



Reply all
Reply to author
Forward
0 new messages