Wednesday, June 27, 2007

Alternative to properties file: YAML beans

Plain ol properties files are great for setting configurations for your apps. But if your configuration requires structured data and you prefer not use XML, there is a great alternative: YAML format and beans.

Let assume we have a config as below. One client and multiple servers.


client:
log: /tmp/client/log
debug: on

servers:
- host: zeus
port: 9510

- host: apollo
port: 9511


Yaml treats the whole config file as a hash map, keys are "client" and "servers". Subsequently, it treats "client" as a another hash map, and "servers" is an array of maps. Sounds complicated but it's straight forward once you're getting a hang of it.

To parse this config, JYaml makes it easier than fixing cereal:


Map config = (Map) YAML.load(new FileReader("config.yml"));

Map client = (Map) config.get("client");
System.out.println("Client: " + client);

List servers = (ArrayList) config.get("servers");
System.out.println("Servers: " + servers);

And output is:

Client: {debug=true, log=/tmp/client/log}
Servers: [{host=zeus, port=9510}, {host=apollo, port=9511}]


You would access client's and server's properties like this:

client.get("log");
Map firstServer = (Map)servers.get(0);
firstServer.get("host");


If you want the config being mapped to Java beans, JYaml can populate the beans for you. This is my preferred way since it's much nicer.

The beans for your config will be as simple as:

/* Top level bean for the whole config */
public class TcConfig {
private List servers;
private Client client;

public List getServers() {
return servers;
}
public void setServers(List servers) {
this.servers = servers;
}
public Client getClient() {
return client;
}
public void setClient(Client client) {
this.client = client;
}
}

/* Client */
public class Client {
private String log;
private boolean debug;

/* getters and setters */

public String toString() {
return "log=" + log + ", debug=" + debug;
}
}

/* Server */
public class Server {
private String host;
private int port;
private String log;

/* getters and setters */

public String toString() {
return "host=" + host + ", port=" + port + ", log=" + log;
}
}


And to populate your beans, just 1 line of code:

TcConfig config = (TcConfig)Yaml.loadType(new File("config.yml"), TcConfig.class);

System.out.println("Servers : " + config.getServers());
System.out.println("Client : " + config.getClient());


XMLBeans can accomplish the same thing with other features like autogenerated Java beans, enforce schema, etc, but for simple things, I prefer Yaml.
Post a Comment