pátek 25. února 2011

Expanze proměnných – neobjevujte kolo

Možná jste už někdy řešili problém, jak nahradit proměnné jejich hodnotou třeba v konfiguračním souboru. Například ze vstupu

<app-config baseDir="${projectDirectory}">
 <timeout>${timeout}</timeout>
</app-config>
chceme ve výsledku dostat
<app-config baseDir="C:\Projects\MyApp">
 <timeout>30</timeout>
</app-config>

Asi vás napadne využít String.replaceAll(String, String) nebo v lepším případě přímo dvojice Pattern/Matcher a capturing groups. Proč ale znovu vymýšlet kolo, když knihovna Apache Commons Lang (která by mimochodem měla být standardní součástí každého netriviálního projektu) nabízí pro daný problém přesně ty třídy, které potřebujeme. Výchozím bodem je třída StrSubstitutor, která obsahuje i statické metody pro zjednodušení v nejpoužívanějších případech:

Map<String, Object> properties = new HashMap<String, Object>();
properties.put("animal", "dog");
properties.put("legs", new Integer(4));

System.out.println(
    StrSubstitutor.replace("The ${animal} has ${legs} legs.", properties));
//prints: The dog has 4 legs. 

StrSubstitutor zvládá nahrazovat i Java property (standardní i ty zadané jako argumenty JVM)

System.out.println(
    StrSubstitutor.replaceSystemProperties("Your OS is '${os.name}'"));
//prints: Your OS is 'Windows XP'

A nejsme vázáni ani zdrojem hodnot našich proměnných. Například, chceme-li expandovat na proměnné prostředí a property mají syntaxi proměnných ve Windows, není to vůbec složité. Stačí vlastní implementace abstraktní třídy StrLookup:

//Anonymous child of StrLookup class, which
//maps property names to environment variables in the system
public static final StrLookup ENV_VAR_LOOKUP = new StrLookup() {
    @Override public String lookup(final String key) {
        return System.getenv(key);
    }
};

//expands windows-like properties to system environment variables (e.g. %PATH%)
public static String expandBatch(final String textToExpand) {
    final StrSubstitutor batchSubstitutor = new StrSubstitutor(
        ENV_VAR_LOOKUP, "%", "%", StrSubstitutor.DEFAULT_ESCAPE);
    return batchSubstitutor.replace(textToExpand);
}

//used then
System.out.println(
    expandBatch("Windows is installed in '%WINDIR%'."));
//prints: Windows is installed in 'C:\WINNT'.

A připomenutí na závěr – neobjevujte znovu kolo – pro začátek si projděte API ke Commons Lang a nebojte se tuto knihovnu používat.

1 komentář:

Tomáš řekl(a)...

Diky za pripomenuti kdyz jsem prochazeil to API tak jsem se pristihl kolik takovych podobnych metod jsem zbytecne napsali, kdyz uz jsou 3x a lepe napsany