BAEL-7617: Intro to Apache Commons Configuration (#16281)
* BAEL-7617: Intro to Apache Commons Configuration * BAEL-7617: Review Comments * BAEL-7617: Review Comments * BAEL-7617: Review Comments
This commit is contained in:
parent
639614cd65
commit
3240f5b820
|
@ -44,6 +44,21 @@
|
||||||
<version>${mockftpserver.version}</version>
|
<version>${mockftpserver.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-configuration2</artifactId>
|
||||||
|
<version>${commons-configuration2.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-beanutils</groupId>
|
||||||
|
<artifactId>commons-beanutils</artifactId>
|
||||||
|
<version>${commons-beanutils.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-jexl</artifactId>
|
||||||
|
<version>${commons-jexl.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.tukaani</groupId>
|
<groupId>org.tukaani</groupId>
|
||||||
<artifactId>xz</artifactId>
|
<artifactId>xz</artifactId>
|
||||||
|
@ -63,6 +78,9 @@
|
||||||
<apache-commons-text.version>1.10.0</apache-commons-text.version>
|
<apache-commons-text.version>1.10.0</apache-commons-text.version>
|
||||||
<commons-net.version>3.6</commons-net.version>
|
<commons-net.version>3.6</commons-net.version>
|
||||||
<mockftpserver.version>2.7.1</mockftpserver.version>
|
<mockftpserver.version>2.7.1</mockftpserver.version>
|
||||||
|
<commons-configuration2.version>2.10.0</commons-configuration2.version>
|
||||||
|
<commons-beanutils.version>1.9.4</commons-beanutils.version>
|
||||||
|
<commons-jexl.version>2.1.1</commons-jexl.version>
|
||||||
<xz.version>1.9</xz.version>
|
<xz.version>1.9</xz.version>
|
||||||
<zstd-jni.version>1.5.5-11</zstd-jni.version>
|
<zstd-jni.version>1.5.5-11</zstd-jni.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.baeldung.commons.configuration;
|
||||||
|
|
||||||
|
import org.apache.commons.configuration2.ConfigurationDecoder;
|
||||||
|
import org.apache.commons.net.util.Base64;
|
||||||
|
|
||||||
|
public class CustomDecoder implements ConfigurationDecoder {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String decode(String encodedValue) {
|
||||||
|
return new String(Base64.decodeBase64(encodedValue));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.baeldung.commons.configuration;
|
||||||
|
|
||||||
|
public class ExternalServices {
|
||||||
|
|
||||||
|
public static final String BAELDUNG_WEBSITE = "https://www.baeldung.com";
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,169 @@
|
||||||
|
package com.baeldung.commons.configuration;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
|
import org.apache.commons.configuration2.AbstractConfiguration;
|
||||||
|
import org.apache.commons.configuration2.Configuration;
|
||||||
|
import org.apache.commons.configuration2.PropertiesConfiguration;
|
||||||
|
import org.apache.commons.configuration2.XMLConfiguration;
|
||||||
|
import org.apache.commons.configuration2.builder.fluent.Configurations;
|
||||||
|
import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler;
|
||||||
|
import org.apache.commons.configuration2.ex.ConfigurationException;
|
||||||
|
import org.apache.commons.configuration2.ex.ConversionException;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
class ConfigurationClassUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenPropertiesFile_whenReadingWithConfigurationClass_thenIsLoaded() throws ConfigurationException {
|
||||||
|
Configurations configs = new Configurations();
|
||||||
|
Configuration config = configs.properties(new File("src/test/resources/configuration/file.properties"));
|
||||||
|
String dbHost = config.getString("db.host");
|
||||||
|
int dbPort = config.getInt("db.port");
|
||||||
|
String dbUser = config.getString("db.user");
|
||||||
|
String dbPassword = config.getString("undefinedKey", "defaultValue");
|
||||||
|
assertEquals("baeldung.com", dbHost);
|
||||||
|
assertEquals(9999, dbPort);
|
||||||
|
assertEquals("admin", dbUser);
|
||||||
|
assertEquals("defaultValue", dbPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenXMLFile_whenReadingWithConfigurationClass_thenIsLoaded() throws ConfigurationException {
|
||||||
|
Configurations configs = new Configurations();
|
||||||
|
XMLConfiguration config = configs.xml(new File("src/test/resources/configuration/hierarchical.xml"));
|
||||||
|
String appender = config.getString("appender[@name]");
|
||||||
|
List<String> encoderPatterns = config.getList(String.class, "appender.encoder.pattern");
|
||||||
|
String pattern1 = config.getString("appender.encoder.pattern(0)");
|
||||||
|
assertEquals("STDOUT", appender);
|
||||||
|
assertEquals(2, encoderPatterns.size());
|
||||||
|
assertEquals("Pattern1", pattern1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenPropertiesFile_whenCopyingConfiguration_thenIsSuccessful() throws ConfigurationException {
|
||||||
|
Configurations configs = new Configurations();
|
||||||
|
Configuration baseConfig = configs.properties(new File("src/test/resources/configuration/file.properties"));
|
||||||
|
Configuration subConfig = new PropertiesConfiguration();
|
||||||
|
subConfig.addProperty("db.host", "baeldung");
|
||||||
|
subConfig.addProperty("db.driver", "dummyDriver");
|
||||||
|
((AbstractConfiguration) subConfig).copy(baseConfig);
|
||||||
|
String dbHost = subConfig.getString("db.host");
|
||||||
|
String dbDriver = subConfig.getString("db.driver");
|
||||||
|
int dbPort = subConfig.getInt("db.port");
|
||||||
|
String dbUser = subConfig.getString("db.user");
|
||||||
|
assertEquals("baeldung.com", dbHost);
|
||||||
|
assertEquals(9999, dbPort);
|
||||||
|
assertEquals("admin", dbUser);
|
||||||
|
assertEquals("dummyDriver", dbDriver);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenPropertiesFile_whenAppendingConfiguration_thenIsSuccessful() throws ConfigurationException {
|
||||||
|
Configurations configs = new Configurations();
|
||||||
|
Configuration baseConfig = configs.properties(new File("src/test/resources/configuration/file.properties"));
|
||||||
|
Configuration subConfig = new PropertiesConfiguration();
|
||||||
|
subConfig.addProperty("db.host", "baeldung");
|
||||||
|
subConfig.addProperty("db.driver", "dummyDriver");
|
||||||
|
((AbstractConfiguration) subConfig).append(baseConfig);
|
||||||
|
String dbHost = subConfig.getString("db.host");
|
||||||
|
String dbDriver = subConfig.getString("db.driver");
|
||||||
|
int dbPort = subConfig.getInt("db.port");
|
||||||
|
String dbUser = subConfig.getString("db.user");
|
||||||
|
assertEquals("baeldung", dbHost);
|
||||||
|
assertEquals(9999, dbPort);
|
||||||
|
assertEquals("admin", dbUser);
|
||||||
|
assertEquals("dummyDriver", dbDriver);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenXMLFile_whenCloningConfiguration_thenIsSuccessful() throws ConfigurationException {
|
||||||
|
Configurations configs = new Configurations();
|
||||||
|
XMLConfiguration baseConfig = configs.xml(new File("src/test/resources/configuration/hierarchical.xml"));
|
||||||
|
XMLConfiguration subConfig = new XMLConfiguration();
|
||||||
|
//subConfig = (XMLConfiguration) baseConfig.clone();
|
||||||
|
subConfig = new XMLConfiguration(baseConfig);
|
||||||
|
String appender = subConfig.getString("appender[@name]");
|
||||||
|
List<String> encoderPatterns = subConfig.getList(String.class, "appender.encoder.pattern");
|
||||||
|
String pattern1 = subConfig.getString("appender.encoder.pattern(0)");
|
||||||
|
assertEquals("STDOUT", appender);
|
||||||
|
assertEquals(2, encoderPatterns.size());
|
||||||
|
assertEquals("Pattern1", pattern1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenEncodedProperty_whenCustomDecoderImplemented_thenIsSuccessful() throws ConfigurationException {
|
||||||
|
Configurations configs = new Configurations();
|
||||||
|
Configuration config = configs.properties(new File("src/test/resources/configuration/file.properties"));
|
||||||
|
((AbstractConfiguration) config).setConfigurationDecoder(new CustomDecoder());
|
||||||
|
assertEquals("mySecretString", config.getEncodedString("db.password"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenDataTypeConversionAttempted_thenIsSuccessful() {
|
||||||
|
Configuration config = new PropertiesConfiguration();
|
||||||
|
config.addProperty("stringProperty", "This is a string");
|
||||||
|
config.addProperty("numericProperty", "9999");
|
||||||
|
config.addProperty("booleanProperty", "true");
|
||||||
|
assertEquals("This is a string", config.getString("stringProperty"));
|
||||||
|
assertEquals(9999, config.getInt("numericProperty"));
|
||||||
|
assertTrue(config.getBoolean("booleanProperty"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenDataTypeConversionAttempted_thenThrowsException() {
|
||||||
|
Configuration config = new PropertiesConfiguration();
|
||||||
|
config.addProperty("numericProperty", "9999a");
|
||||||
|
assertThrows(ConversionException.class, () -> config.getInt("numericProperty"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenInterpolationIsAttempted_thenIsSuccessful() throws ConfigurationException {
|
||||||
|
System.setProperty("user.name", "Baeldung");
|
||||||
|
Configurations configs = new Configurations();
|
||||||
|
Configuration config = configs.properties(new File("src/test/resources/configuration/file.properties"));
|
||||||
|
String dbUrl = config.getString("db.url");
|
||||||
|
String userName = config.getString("db.username");
|
||||||
|
String externalService = config.getString("db.external-service");
|
||||||
|
assertEquals("baeldung.com:9999", dbUrl);
|
||||||
|
assertEquals("Baeldung", userName);
|
||||||
|
assertEquals("https://www.baeldung.com", externalService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenDelimiterIsSpecified_thenMultiValuePropertyIsLoaded() {
|
||||||
|
PropertiesConfiguration propertiesConfig = new PropertiesConfiguration();
|
||||||
|
propertiesConfig.setListDelimiterHandler(new DefaultListDelimiterHandler(';'));
|
||||||
|
propertiesConfig.addProperty("delimitedProperty", "admin;read-only;read-write");
|
||||||
|
propertiesConfig.addProperty("arrayProperty", "value1;value2");
|
||||||
|
List<Object> delimitedProperties = propertiesConfig.getList("delimitedProperty");
|
||||||
|
String[] arrayProperties = propertiesConfig.getStringArray("arrayProperty");
|
||||||
|
assertEquals(3, delimitedProperties.size());
|
||||||
|
assertEquals("admin", delimitedProperties.get(0));
|
||||||
|
assertEquals(2, arrayProperties.length);
|
||||||
|
assertEquals("value1", propertiesConfig.getString("arrayProperty"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenPropertiesAreMissing_thenIsHandled() {
|
||||||
|
PropertiesConfiguration propertiesConfig = new PropertiesConfiguration();
|
||||||
|
String objectProperty = propertiesConfig.getString("anyProperty");
|
||||||
|
int primitiveProperty = propertiesConfig.getInt("anyProperty", 1);
|
||||||
|
assertNull(objectProperty);
|
||||||
|
assertEquals(1, primitiveProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenPropertiesAreMissing_thenExceptionIsThrown() {
|
||||||
|
PropertiesConfiguration propertiesConfig = new PropertiesConfiguration();
|
||||||
|
assertThrows(NoSuchElementException.class, () -> propertiesConfig.getInt("anyProperty"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package com.baeldung.commons.configuration;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.configuration2.Configuration;
|
||||||
|
import org.apache.commons.configuration2.FileBasedConfiguration;
|
||||||
|
import org.apache.commons.configuration2.PropertiesConfiguration;
|
||||||
|
import org.apache.commons.configuration2.XMLConfiguration;
|
||||||
|
import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
|
||||||
|
import org.apache.commons.configuration2.builder.fluent.Parameters;
|
||||||
|
import org.apache.commons.configuration2.ex.ConfigurationException;
|
||||||
|
import org.apache.commons.configuration2.interpol.ConfigurationInterpolator;
|
||||||
|
import org.apache.commons.configuration2.interpol.ExprLookup;
|
||||||
|
import org.apache.commons.configuration2.interpol.Lookup;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
class FileBasedConfigurationBuilderUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenReadingPropertiesFile_thenIsSuccessful() throws ConfigurationException {
|
||||||
|
Parameters params = new Parameters();
|
||||||
|
FileBasedConfigurationBuilder<FileBasedConfiguration> builder = new FileBasedConfigurationBuilder<FileBasedConfiguration>(
|
||||||
|
PropertiesConfiguration.class).configure(params.properties()
|
||||||
|
.setFileName("src/test/resources/configuration/file1.properties"));
|
||||||
|
Configuration config = builder.getConfiguration();
|
||||||
|
String dbHost = config.getString("db.host");
|
||||||
|
int dbPort = config.getInt("db.port");
|
||||||
|
String dbUser = config.getString("db.user");
|
||||||
|
assertEquals("baeldung.com", dbHost);
|
||||||
|
assertEquals(9999, dbPort);
|
||||||
|
assertEquals("admin", dbUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenReadingXMLFile_thenIsSuccessful() throws ConfigurationException {
|
||||||
|
Parameters params = new Parameters();
|
||||||
|
FileBasedConfigurationBuilder<XMLConfiguration> builder = new FileBasedConfigurationBuilder<>(XMLConfiguration.class).configure(params.xml()
|
||||||
|
.setFileName("src/test/resources/configuration/hierarchical.xml")
|
||||||
|
.setValidating(true));
|
||||||
|
XMLConfiguration config = builder.getConfiguration();
|
||||||
|
String appender = config.getString("appender[@name]");
|
||||||
|
List<String> encoderPatterns = config.getList(String.class, "appender.encoder.pattern");
|
||||||
|
assertEquals("STDOUT", appender);
|
||||||
|
assertEquals(2, encoderPatterns.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenExpressionEvaluationIsAttempted_thenIsSuccessful() throws ConfigurationException {
|
||||||
|
System.setProperty("user.home", "/usr/lib");
|
||||||
|
Parameters params = new Parameters();
|
||||||
|
Map<String, Lookup> lookups = new HashMap<>(ConfigurationInterpolator.getDefaultPrefixLookups());
|
||||||
|
ExprLookup.Variables variables = new ExprLookup.Variables();
|
||||||
|
variables.add(new ExprLookup.Variable("System", "Class:java.lang.System"));
|
||||||
|
ExprLookup exprLookup = new ExprLookup(variables);
|
||||||
|
exprLookup.setInterpolator(new ConfigurationInterpolator());
|
||||||
|
lookups.put("expr", exprLookup);
|
||||||
|
FileBasedConfigurationBuilder<FileBasedConfiguration> builder = new FileBasedConfigurationBuilder<FileBasedConfiguration>(
|
||||||
|
PropertiesConfiguration.class).configure(params.properties()
|
||||||
|
.setFileName("src/test/resources/configuration/file1.properties")
|
||||||
|
.setPrefixLookups(lookups));
|
||||||
|
Configuration config = builder.getConfiguration();
|
||||||
|
String dbDumpLocation = config.getString("db.data-dump-location");
|
||||||
|
assertEquals("/usr/lib/dump.dat", dbDumpLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.baeldung.commons.configuration;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import org.apache.commons.configuration2.Configuration;
|
||||||
|
import org.apache.commons.configuration2.PropertiesConfiguration;
|
||||||
|
import org.apache.commons.configuration2.builder.combined.MultiFileConfigurationBuilder;
|
||||||
|
import org.apache.commons.configuration2.builder.fluent.Parameters;
|
||||||
|
import org.apache.commons.configuration2.ex.ConfigurationException;
|
||||||
|
import org.apache.commons.configuration2.interpol.ConfigurationInterpolator;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
class MultiFileConfigurationBuilderUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenMultiplePropertyFiles_whenReadingWithMultiFileConfigurationBuilder_thenIsLoaded() throws ConfigurationException {
|
||||||
|
System.setProperty("tenant", "A");
|
||||||
|
String filePattern = "src/test/resources/configuration/tenant-${sys:tenant}.properties";
|
||||||
|
MultiFileConfigurationBuilder<PropertiesConfiguration> builder = new MultiFileConfigurationBuilder<>(PropertiesConfiguration.class).configure(
|
||||||
|
new Parameters().multiFile()
|
||||||
|
.setFilePattern(filePattern)
|
||||||
|
.setPrefixLookups(ConfigurationInterpolator.getDefaultPrefixLookups()));
|
||||||
|
Configuration config = builder.getConfiguration();
|
||||||
|
String tenantAName = config.getString("name");
|
||||||
|
|
||||||
|
assertEquals("Tenant A", tenantAName);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
db.host=baeldung.com
|
||||||
|
db.port=9999
|
||||||
|
db.user=admin
|
||||||
|
db.password=bXlTZWNyZXRTdHJpbmc=
|
||||||
|
db.url=${db.host}:${db.port}
|
||||||
|
db.username=${sys:user.name}
|
||||||
|
db.external-service=${const:com.baeldung.commons.configuration.ExternalServices.BAELDUNG_WEBSITE}
|
||||||
|
db.data-dump-location=${expr:System.getProperty("user.home")}/dump.dat
|
|
@ -0,0 +1,4 @@
|
||||||
|
db.host=baeldung.com
|
||||||
|
|
||||||
|
include=file.properties
|
||||||
|
includeOptional=file2.properties
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE configuration SYSTEM "validation-sample.dtd">
|
||||||
|
<configuration>
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>Pattern1</pattern>
|
||||||
|
<pattern>Pattern2</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<root>
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
|
@ -0,0 +1 @@
|
||||||
|
name=Tenant A
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!ELEMENT configuration (appender+, root)>
|
||||||
|
<!ELEMENT appender (encoder?)>
|
||||||
|
<!ATTLIST appender
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
class CDATA #REQUIRED
|
||||||
|
>
|
||||||
|
<!ELEMENT encoder (pattern+)>
|
||||||
|
<!ELEMENT pattern (#PCDATA)>
|
||||||
|
<!ELEMENT root (appender-ref+)>
|
||||||
|
<!ELEMENT appender-ref EMPTY>
|
||||||
|
<!ATTLIST appender-ref
|
||||||
|
ref CDATA #REQUIRED
|
||||||
|
>
|
Loading…
Reference in New Issue