Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[CONJ-1032] option case-insensitive for compatibility with 2.x
  • Loading branch information
rusher committed Dec 21, 2022
1 parent 6d31ce6 commit 1d9bee5
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 45 deletions.
89 changes: 49 additions & 40 deletions src/main/java/org/mariadb/jdbc/Configuration.java
Expand Up @@ -603,55 +603,64 @@ private static void mapPropertiesToOption(Builder builder, Properties properties
// loop on properties,
// - check DefaultOption to check that property value correspond to type (and range)
// - set values
for (final Object keyObj : properties.keySet()) {
String realKey = OptionAliases.OPTIONS_ALIASES.get(keyObj);
if (realKey == null) realKey = keyObj.toString();
final Object propertyValue = properties.get(keyObj);

if (propertyValue != null && realKey != null) {
try {
final Field field = Builder.class.getDeclaredField(realKey);
field.setAccessible(true);
if (field.getGenericType().equals(String.class)
&& !propertyValue.toString().isEmpty()) {
field.set(builder, propertyValue);
} else if (field.getGenericType().equals(Boolean.class)) {
switch (propertyValue.toString().toLowerCase()) {
case "":
case "1":
case "true":
field.set(builder, Boolean.TRUE);
break;

case "0":
case "false":
field.set(builder, Boolean.FALSE);
break;

default:
Properties remainingProperties = new Properties();
properties.forEach((key, val) -> remainingProperties.put(key, val));

for (Field field : Builder.class.getDeclaredFields()) {
if (remainingProperties.isEmpty()) break;
for (final Object keyObj : remainingProperties.keySet()) {
String realKey =
OptionAliases.OPTIONS_ALIASES.get(keyObj.toString().toLowerCase(Locale.ROOT));
if (realKey == null) realKey = keyObj.toString();
final Object propertyValue = remainingProperties.get(keyObj);

if (propertyValue != null && realKey != null) {
if (realKey.toLowerCase(Locale.ROOT).equals(field.getName().toLowerCase(Locale.ROOT))) {
field.setAccessible(true);
remainingProperties.remove(keyObj);

if (field.getGenericType().equals(String.class)
&& !propertyValue.toString().isEmpty()) {
field.set(builder, propertyValue);
} else if (field.getGenericType().equals(Boolean.class)) {
switch (propertyValue.toString().toLowerCase()) {
case "":
case "1":
case "true":
field.set(builder, Boolean.TRUE);
break;

case "0":
case "false":
field.set(builder, Boolean.FALSE);
break;

default:
throw new IllegalArgumentException(
String.format(
"Optional parameter %s must be boolean (true/false or 0/1) was '%s'",
keyObj, propertyValue));
}
} else if (field.getGenericType().equals(Integer.class)) {
try {
final Integer value = Integer.parseInt(propertyValue.toString());
field.set(builder, value);
} catch (NumberFormatException n) {
throw new IllegalArgumentException(
String.format(
"Optional parameter %s must be boolean (true/false or 0/1) was '%s'",
"Optional parameter %s must be Integer, was '%s'",
keyObj, propertyValue));
}
} else if (field.getGenericType().equals(Integer.class)) {
try {
final Integer value = Integer.parseInt(propertyValue.toString());
field.set(builder, value);
} catch (NumberFormatException n) {
throw new IllegalArgumentException(
String.format(
"Optional parameter %s must be Integer, was '%s'", keyObj, propertyValue));
}
}
}
} catch (NoSuchFieldException nfe) {
// keep unknown option:
// those might be used in authentication or identity plugin
nonMappedOptions.put(keyObj, propertyValue);
}
}
}

// keep unknown option:
// those might be used in authentication or identity plugin
remainingProperties.forEach((key, val) -> nonMappedOptions.put(key, val));

// for compatibility with 2.x
if (isSet("useSsl", nonMappedOptions) || isSet("useSSL", nonMappedOptions)) {
if (isSet("trustServerCertificate", nonMappedOptions)) {
Expand Down
Expand Up @@ -15,10 +15,8 @@ public final class OptionAliases {

static {
OPTIONS_ALIASES = new HashMap<>();
OPTIONS_ALIASES.put("enabledSSLCipherSuites", "enabledSslCipherSuites");
OPTIONS_ALIASES.put("serverRSAPublicKeyFile", "serverRsaPublicKeyFile");
OPTIONS_ALIASES.put("clientCertificateKeyStoreUrl", "keyStore");
OPTIONS_ALIASES.put("clientCertificateKeyStorePassword", "keyStorePassword");
OPTIONS_ALIASES.put("clientCertificateKeyStoreType", "keyStoreType");
OPTIONS_ALIASES.put("clientcertificatekeystoreurl", "keyStore");
OPTIONS_ALIASES.put("clientcertificatekeystorepassword", "keyStorePassword");
OPTIONS_ALIASES.put("clientcertificatekeystoretype", "keyStoreType");
}
}
15 changes: 15 additions & 0 deletions src/test/java/org/mariadb/jdbc/unit/util/ConfigurationTest.java
Expand Up @@ -306,6 +306,21 @@ public void testOptionParse() throws Throwable {
assertEquals("toto", conf.password());
}

@Test
public void nonCaseSensitiveOptions() throws Throwable {
Configuration conf =
Configuration.parse(
"jdbc:mariadb://localhost/test?useR=root&paSsword=toto&createdb=true"
+ "&autoReConnect=true&prepStMtCacheSize=2&ConnectTimeout=5&socketTimeout=20");
assertEquals(5, conf.connectTimeout());
assertEquals(20, conf.socketTimeout());
assertEquals(2, conf.prepStmtCacheSize());
assertEquals("true", conf.nonMappedOptions().get("createdb"));
assertEquals("true", conf.nonMappedOptions().get("autoReConnect"));
assertEquals("root", conf.user());
assertEquals("toto", conf.password());
}

@Test
public void wrongTypeParsing() {
Common.assertThrowsContains(
Expand Down

0 comments on commit 1d9bee5

Please sign in to comment.