1 /** 2 * Utilities for loading Java properties files. 3 * 4 * Authors: 5 * Mike Bierlee, m.bierlee@lostmoment.com 6 * Copyright: 2022-2025 Mike Bierlee 7 * License: 8 * This software is licensed under the terms of the MIT license. 9 * The full terms of the license can be found in the LICENSE file. 10 */ 11 12 module mirage.java; 13 14 import mirage.config : ConfigDictionary; 15 import mirage.keyvalue : KeyValueConfigFactory, SupportHashtagComments, SupportSemicolonComments, 16 SupportExclamationComments, SupportSections, NormalizeQuotedValues, SupportEqualsSeparator, 17 SupportColonSeparator, SupportKeysWithoutValues, SupportMultilineValues; 18 19 /** 20 * Creates configuration dictionaries from Java properties. 21 * 22 * Format specifications: 23 * https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Properties.html#load(java.io.Reader) 24 * https://en.wikipedia.org/wiki/.properties 25 */ 26 class JavaPropertiesFactory : KeyValueConfigFactory!( 27 SupportHashtagComments.yes, 28 SupportSemicolonComments.no, 29 SupportExclamationComments.yes, 30 SupportSections.no, 31 NormalizeQuotedValues.no, 32 SupportEqualsSeparator.yes, 33 SupportColonSeparator.yes, 34 SupportKeysWithoutValues.yes, 35 SupportMultilineValues.yes 36 ) { 37 } 38 39 /** 40 * Parse Java properties from the given Java properties string. 41 42 * Params: 43 * properties = Text contents of the config to be parsed. 44 * Returns: The parsed configuration. 45 */ 46 ConfigDictionary parseJavaProperties(const string properties) { 47 return new JavaPropertiesFactory().parseConfig(properties); 48 } 49 50 /// ditto 51 alias parseJavaConfig = parseJavaProperties; 52 53 /** 54 * Load a Java properties file from disk. 55 * 56 * Params: 57 * filePath = Path to the Java properties file. 58 * Returns: The loaded configuration. 59 */ 60 ConfigDictionary loadJavaProperties(const string filePath) { 61 return new JavaPropertiesFactory().loadFile(filePath); 62 } 63 64 /// ditto 65 alias loadJavaConfig = loadJavaProperties; 66 67 version (unittest) { 68 import std.exception : assertThrown; 69 import std.process : environment; 70 import mirage.config : ConfigCreationException; 71 72 @("Parse java properties") 73 unittest { 74 auto config = parseJavaProperties(" 75 # I have a comment 76 bla=one 77 di.bla=two 78 meh: very # except when meh=not very 79 much = not much 80 much: much !important!!!!!!!! 81 empty 82 multi = we are \\ 83 two lines 84 "); 85 86 assert(config.get("bla") == "one"); 87 assert(config.get("di.bla") == "two"); 88 assert(config.get("meh") == "very"); 89 assert(config.get("much") == "much"); 90 assert(config.get("empty") == ""); 91 assert(config.get("multi") == "we are two lines"); 92 } 93 94 @("Parse java properties file") 95 unittest { 96 auto config = loadJavaProperties("testfiles/java.properties"); 97 assert(config.get("bla") == "one"); 98 assert(config.get("di.bla") == "two"); 99 } 100 101 @("Substitute env vars") 102 unittest { 103 environment["MIRAGE_TEST_ENVY"] = "Much"; 104 auto config = parseJavaProperties("envy=$MIRAGE_TEST_ENVY"); 105 106 assert(config.get("envy") == "Much"); 107 } 108 109 @("Use value from other key") 110 unittest { 111 auto config = parseJavaProperties(" 112 one=money 113 two=${one} 114 "); 115 116 assert(config.get("two") == "money"); 117 } 118 119 @("Values and keys are trimmed") 120 unittest { 121 auto config = parseJavaConfig(" 122 one = money 123 "); 124 125 assert(config.get("one") == "money"); 126 } 127 128 @("Quotes in values are preserved") 129 unittest { 130 auto config = parseJavaProperties(" 131 one=\"two\" 132 three='four' 133 "); 134 135 assert(config.get("one") == "\"two\""); 136 assert(config.get("three") == "'four'"); 137 } 138 }