
bracket-properties
August 4th, 2015 - Code Hosted on a NEW SITE: https://www.cryptoregistry.com/ Please visit
April 19 2014 - Version 1.3.5 is now available through Maven Central. Use the following coordinates in your pom.xml file:
- groupId: asia.redact.bracket.properties
- artifactId: bracket-properties
- version: 1.3.5
You Tube
Introduction
It does not take much experience with the java.util.Properties class to understand it could be improved.
Bracket Properties is a re-tune of the Properties concept from the ground up, while keeping the ubiquitous .properties file format intact. It offers a number of improvements:
- It is not a map (does not implement the Map Interface), but rather it has a Map, so there is no ambiguity about the types of keys and values.
- The design is more object-oriented and hopefully clearer and more robust, with a Lexer, Parser, and so on
- Order of properties is maintained across serialization
- Comments are maintained across serialization
- Serialization output can be controlled and customized in user-defined ways
- I18n localization is simple and elegant
- Multi-line values are handled more easily and maintained across serialization
- Handles list properties
- Provides a solution for externalized configurations
In addition, Bracket Properties provides innovations which are novel and potentially enlightening:
- Provides an arguably better XML serialization format
- Provides methods that return a tree-like data structure, for working with properties in a tree-like manner
- Provides a way to work with groups of properties (properties with related key structure or roots)
Bracket Properties is compiled for Java version 1.6 (Java 6) and above. It will not work with Java versions 1.5 or below. It has only one dependency, log4j.
Cookbook
Instantiating Properties
Use the factory to get an implementation of the Properties Interface: ``` Properties.Factory.getInstance(); // return an empty properties object
// Get properties from various input sources
Reader reader = new FileReader("file.properties");
Properties props = Properties.Factory.getInstance(reader);
File file = new File("file.properties");
Properties props = Properties.Factory.getInstance(file, Charset.forName("UTF-8");
InputStream in = getClass().getResourceAsStream("/log4j-example.properties");
Properties props = Properties.Factory.getInstance(in);
URL url = new URL("http://www.somewhere.com/getProps");
Properties props = Properties.Factory.getInstance(url);
```
More exotic use cases can be supported by parsing the properties input directly: ``` String input = "# comment\ns1=value1\ns2=value2"; PropertiesLexer lexer = new PropertiesLexer(input); lexer.lex(); List list = lexer.getList(); Properties props = new PropertiesImpl(); new PropertiesParser(list, props).parse(); Assert.assertEqual("value1", props.get("s1"));
```
Convert an existing java.util.Properties object into a Bracket Properties object:
java.util.Properties props = new Properties(); props.load(somefile); Properties bracketProps = Properties.Factory.getInstance(props);
Using Properties
Bracket Properties provides what you might expect in the form of get() plus some additional support for accessing properties:
``` Properties props; // ... String value = props.get("key"); //typical invocation List comments = props.getComments("key"); // a (potentially empty) list of associated comments char separator = props.getSeparator("key"); // the separator on this key/value pair, usually "="
```
There are also some convenience conversion methods provided to get numbers out of a property value:
Properties props = Properties.Factory.getInstance(); props.put("anInteger", String.valueOf(1000)); int val = props.intValue("anInteger"); long longVal = props.longValue("anInteger");
And a Date extractor as well:
Properties props = Properties.Factory.getInstance();
props.put("aDate", String.valueOf(1323568727353));
Date date = props.dateValue("aDate");
As of Revision 160, accessing lists are supported in a natural way:
Data:
```
list properties
wrapper.java.classpath.1=../lib/wrapper.jar wrapper.java.classpath.2=../lib/myapp.jar wrapper.java.classpath.3=../lib/mysql.jar wrapper.java.classpath.4=../classes wrapper.java.classpath.10=../lib/wrapper2.jar ```
Get the properties as a list:
InputStream in = getClass().getResourceAsStream("/ListResources/list.properties");
Properties props = Properties.Factory.getInstance(in);
List<String> list = props.getList("wrapper.java.classpath");
StringBuffer classpath = new StringBuffer();
int i = 0;
for(String s: list){
classpath.append(s);
if(i<list.size()-1)classpath.append(File.pathSeparator);
i++;
}
System.err.println(classpath.toString());
Which outputs:
../lib/wrapper.jar;../lib/myapp.jar;../lib/mysql.jar;../classes;../lib/wrapper2.jar
As of Revision 175, you can create list properties using putList():
List<String> fruit = new ArrayList<String>();
fruit.add("apple");
fruit.add("orange");
fruit.add("banana");
props.putList(fruit, "fruit");
This will create keys like
fruit.0=apple
fruit.1=orange
fruit.2=banana
Property Map
To get access to the underlying data structure, including comments, use the underlying properties map:
LinkedHashMap<String, ValueModel> map = props.getPropertyMap();
As of version 1.3.2, ValueModel is an interface. The below applies now to BasicValueModel:
BasicValueModel is a Value Object (in the design pattern sense) and has the following structure:
```
public class BasicValueModel implements ValueModel {
protected final List<String> comments;
protected final List<String> values;
protected char separator = '=';
// ...accessors
}
```
It has addValue(), addComment(), and clearComments() methods in addition to the usual accessors.
Serialization
Bracket Properties takes the position that the Properties class itself should not be in the business of serialization; other classes should perform this role. An OutputAdapter is provided for this purpose:
``` OutputAdapter out = new OutputAdapter(props); Writer w = new StringWriter(); try { out.writeTo(w); } catch (IOException e) { e.printStackTrace(); }
```
This will produce useful default output including a timestamped header and end footer using BasicOutputFormat.
Besides a good default serializer, Bracket Properties provides opportunities to customize the basic .properties file output. The OutputAdapter has writeTo(File) and writeTo(Writer). writeTo(OutputStream) is not provided, as properties files by definition are always text files.
To custom format the output, an interface called OutputFormat is provided:
```
public interface OutputFormat {
public String formatHeader();
public String format(String key, char sep, List<String> values, List<String> comments);
public String formatFooter();
}
```
For example,
``` MyOutputFormat format = new MyOutputFormat(); OutputAdapter out = new OutputAdapter(props); Writer w = new StringWriter(); try { out.writeTo(w, format); } catch (IOException e) { e.printStackTrace(); }
```
For the common case of java.util.Properties compatibility in US-ASCII encoding with embedded unicode escapes, AsciiOutputFormat is provided:
AsciiOutputFormat format = new AsciiOutputFormat();
OutputAdapter out = new OutputAdapter(props);
File file = new File("my.properties");
try {
out.writeAsciiTo(file,format);
} catch (IOException e) {
e.printStackTrace();
}
or just use
out.writeAsciiTo(file);
Groups of Properties
It is common to organize property keys using dot notation, such as
``` // ... a.b.c.s1=this a.b.c.s2=that a.b.c.s3=another // ...
```
An easy way of working with a group of related properties is to pull them out as a group:
Properties abcs = props.getGroup(new GroupParams("a.b.c"));
// abcs has only the above three items
Assert.assertEquals(3,abcs.size());
Tree-like Operations
Very often there is a tree-like structure present in the keys because it is there in the program. We can use this observation to work with properties in a more tree-like way:
InputStream in = getClass().getResourceAsStream("/log4j.properties");
Properties props = Properties.Factory.getInstance(in);
Node node = props.getTree().getDescendant("log4j.appender.FILE");
if(node.hasValue()){
Assert.assertEquals("org.apache.log4j.FileAppender", node.value.getValue());
}
XML Format
The bracket XML format is a bit different then the default Sun DTD. Suppose you have a Properties file called input.properties containing:
a.b.c=value
a.b.c.d=subvalue1
a.b.c.e=subvalue2
This could be serialized to XML using the following:
InputStream in = getClass().getResourceAsStream("/xml/input0.properties");
Properties props = Properties.Factory.getInstance(in);
OutputAdapter outAdapter = new OutputAdapter(props);
File temp;
try {
temp = File.createTempFile("test", "xml");
FileWriter writer = new FileWriter(temp);
outAdapter.writeAsXml(writer);
writer.close();
} catch (IOException e) {}
The output looks like this:
<?xml version="1.0" encoding="ISO-8859-1"?>
<nproperties xmlns="http://code.google.com/p/bracket-properties">
<na>
<nb>
<nc>
<s>=</s>
<v><![CDATA[value]]></v>
<nd>
<s>=</s>
<v><![CDATA[subvalue1]]></v>
</nd>
<ne>
<s>=</s>
<v><![CDATA[subvalue2]]></v>
</ne>
</nc>
</nb>
</na>
</nproperties>
More details about this serialization can be found in the wiki under XMLFormat.
Easy I18N
To use Bracket Properties with java Resources (like a Resource Bundle) use the Factory method with the base name and Locale:
``` Properties.Factory.mode = Mode.Compatibility; Properties props = Properties.Factory.getInstance("TestLocaleProps", Locale.ITALY); Assert.assertEquals("Albero", props.get("s1")); props = Properties.Factory.getInstance("TestLocaleProps", Locale.ITALIAN); Assert.assertEquals("Albero", props.get("s1")); props = Properties.Factory.getInstance("TestLocaleProps", Locale.getDefault()); Assert.assertEquals("Tree", props.get("s1"));
```
Easy Externalization of Configurations
``` // some externalized properties in user.home String home = System.getProperty("user.home"); String adminExternalProps = home+File.separator+"administrator.properties";
// some properties loaded from an embedded config file in the app
String templateProps = "/template.properties";
List<PropertiesReference> refs = new ArrayList<PropertiesReference>();
refs.add(new PropertiesReference(ReferenceType.CLASSLOADED,templateProps));
refs.add(new PropertiesReference(ReferenceType.EXTERNAL,adminExternalProps));
Properties props = Properties.Factory.loadReferences(refs);
```
See ExternalizingConfigurations for the rationale.
Project Information
The project was created on Nov 7, 2011.
- License: Apache License 2.0
- 8 stars
- svn-based source control
Labels:
Java
Properties
improved
comments-retained
Middleware
Maven
UTF-8
internationalization
i18n