From 82756a65b2dae87ed185c217695ffa7a666f04d3 Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Tue, 7 Nov 2023 12:17:07 +0000 Subject: [PATCH] Fix StringUtil.skewer to properly convert camelCase and upper case names (#1042) --- .../config/common/utils/StringUtil.java | 95 +++++++------------ .../config/common/utils/StringUtilTest.java | 30 +++++- .../smallrye/config/ImplicitConverters.java | 3 +- .../config/ImplicitConverterTest.java | 6 +- 4 files changed, 67 insertions(+), 67 deletions(-) diff --git a/common/src/main/java/io/smallrye/config/common/utils/StringUtil.java b/common/src/main/java/io/smallrye/config/common/utils/StringUtil.java index 31f4f4370..598f56923 100644 --- a/common/src/main/java/io/smallrye/config/common/utils/StringUtil.java +++ b/common/src/main/java/io/smallrye/config/common/utils/StringUtil.java @@ -299,77 +299,52 @@ public static String skewer(String camelHumps) { } public static String skewer(String camelHumps, char separator) { - return skewer(camelHumps, 0, camelHumps.length(), new StringBuilder(), separator); - } - - private static String skewer(String camelHumps, int start, int end, StringBuilder b, char separator) { + int end = camelHumps.length(); + StringBuilder b = new StringBuilder(); if (camelHumps.isEmpty()) { throw new IllegalArgumentException("Method seems to have an empty name"); } - int cp = camelHumps.codePointAt(start); - b.appendCodePoint(Character.toLowerCase(cp)); - start += Character.charCount(cp); - if (start == end) { - // a lonely character at the end of the string - return b.toString(); - } - if (Character.isUpperCase(cp)) { - // all-uppercase words need one code point of lookahead - int nextCp = camelHumps.codePointAt(start); - if (Character.isUpperCase(nextCp)) { - // it's some kind of `WORD` - for (;;) { - b.appendCodePoint(Character.toLowerCase(nextCp)); - start += Character.charCount(cp); - cp = nextCp; - if (start == end) { - return b.toString(); - } - nextCp = camelHumps.codePointAt(start); - // combine non-letters in with this name - if (Character.isLowerCase(nextCp)) { + + for (int i = 0; i < end; i++) { + char c = camelHumps.charAt(i); + if (Character.isLowerCase(c)) { + b.append(c); + } else if (Character.isUpperCase(c)) { + if (i > 0) { + char last = camelHumps.charAt(i - 1); + if (last != '_' && last != '-') { b.append(separator); - return skewer(camelHumps, start, end, b, separator); } } - // unreachable - } else { - // it was the start of a `Word`; continue until we hit the end or an uppercase. - b.appendCodePoint(nextCp); - start += Character.charCount(nextCp); - for (;;) { - if (start == end) { - return b.toString(); + b.append(Character.toLowerCase(c)); + int j = i + 1; + for (; j < end; j++) { + char u = camelHumps.charAt(j); + if (Character.isUpperCase(u) || Character.isDigit(u)) { + b.append(Character.toLowerCase(u)); + } else { + if (j > i + 1 && u != '_') { + b.insert(b.length() - 1, separator); + } + j--; + break; } - cp = camelHumps.codePointAt(start); - // combine non-letters in with this name - if (Character.isUpperCase(cp)) { + } + i = j; + } else if (Character.isDigit(c)) { + b.append(c); + } else { + if (i > 0) { + char last = camelHumps.charAt(i - 1); + if (last != '_' && last != '-') { b.append(separator); - return skewer(camelHumps, start, end, b, separator); } - b.appendCodePoint(cp); - start += Character.charCount(cp); - } - // unreachable - } - // unreachable - } else { - // it's some kind of `word` - for (;;) { - cp = camelHumps.codePointAt(start); - // combine non-letters in with this name - if (Character.isUpperCase(cp)) { - b.append(separator); - return skewer(camelHumps, start, end, b, separator); - } - b.appendCodePoint(cp); - start += Character.charCount(cp); - if (start == end) { - return b.toString(); + } else { + b.append(c); } } - // unreachable } - // unreachable + + return b.toString(); } } diff --git a/common/src/test/java/io/smallrye/config/common/utils/StringUtilTest.java b/common/src/test/java/io/smallrye/config/common/utils/StringUtilTest.java index a26803c61..cf1dc9fe6 100644 --- a/common/src/test/java/io/smallrye/config/common/utils/StringUtilTest.java +++ b/common/src/test/java/io/smallrye/config/common/utils/StringUtilTest.java @@ -98,20 +98,46 @@ void escapingSituations() { @Test void skewer() { + assertEquals("sigusr1", StringUtil.skewer("sigusr1")); + assertThrows(IllegalArgumentException.class, () -> StringUtil.skewer("")); assertThrows(IllegalArgumentException.class, () -> StringUtil.skewer("", '.')); assertEquals("my-property", StringUtil.skewer("myProperty")); assertEquals("my.property", StringUtil.skewer("myProperty", '.')); + assertEquals("-", StringUtil.skewer("-")); + assertEquals("_", StringUtil.skewer("_")); assertEquals("a", StringUtil.skewer("a")); + assertEquals("a", StringUtil.skewer("A")); assertEquals("a", StringUtil.skewer("a", '.')); + assertEquals("a-b", StringUtil.skewer("a-b")); + assertEquals("_a", StringUtil.skewer("_a")); + assertEquals("_a-b", StringUtil.skewer("_a_b")); assertEquals("my-property-abc", StringUtil.skewer("myPropertyABC")); assertEquals("my.property.abc", StringUtil.skewer("myPropertyABC", '.')); - assertEquals("my-property-abc-abc", StringUtil.skewer("myPropertyABCabc")); - assertEquals("my.property.abc.abc", StringUtil.skewer("myPropertyABCabc", '.')); + assertEquals("my-property-ab-cabc", StringUtil.skewer("myPropertyABCabc")); + assertEquals("my.property.ab.cabc", StringUtil.skewer("myPropertyABCabc", '.')); + + assertEquals("is-same-rm-override", StringUtil.skewer("isSameRMOverride")); + assertEquals("http-client-http-conduit-factory", StringUtil.skewer("HttpClientHTTPConduitFactory")); + assertEquals("url-connection-http-conduit-factory", StringUtil.skewer("URLConnectionHTTPConduitFactory")); + assertEquals("abc-default", StringUtil.skewer("ABCDefault")); + assertEquals("abc", StringUtil.skewer("ABC")); + + assertEquals("discard", StringUtil.skewer("discard")); + assertEquals("a-b", StringUtil.skewer("A_B")); + assertEquals("read-uncommitted", StringUtil.skewer("READ_UNCOMMITTED")); + assertEquals("_read-uncommitted", StringUtil.skewer("_READ_UNCOMMITTED")); + assertEquals("read-uncommitted", StringUtil.skewer("READ__UNCOMMITTED")); + assertEquals("_read-uncommitted", StringUtil.skewer("_READ__UNCOMMITTED")); + assertEquals("sigusr1", StringUtil.skewer("SIGUSR1")); + assertEquals("sigusr1", StringUtil.skewer("sigusr1")); + assertEquals("trend-breaker", StringUtil.skewer("TrendBreaker")); + assertEquals("making-life-difficult", StringUtil.skewer("MAKING_LifeDifficult")); + assertEquals("making-life-difficult", StringUtil.skewer("makingLifeDifficult")); } @Test diff --git a/implementation/src/main/java/io/smallrye/config/ImplicitConverters.java b/implementation/src/main/java/io/smallrye/config/ImplicitConverters.java index 868ab2c4f..a3fc35339 100644 --- a/implementation/src/main/java/io/smallrye/config/ImplicitConverters.java +++ b/implementation/src/main/java/io/smallrye/config/ImplicitConverters.java @@ -234,8 +234,7 @@ public E convert(final String value) throws IllegalArgumentException, NullPointe } private static String hyphenate(String value) { - // We cannot be sure about the format of the enum names - return StringUtil.skewer(value).replaceAll("_-", "-").replaceAll("_", "-"); + return StringUtil.skewer(value); } } } diff --git a/implementation/src/test/java/io/smallrye/config/ImplicitConverterTest.java b/implementation/src/test/java/io/smallrye/config/ImplicitConverterTest.java index 7dc03df09..ecf3c92ec 100644 --- a/implementation/src/test/java/io/smallrye/config/ImplicitConverterTest.java +++ b/implementation/src/test/java/io/smallrye/config/ImplicitConverterTest.java @@ -92,7 +92,7 @@ public void convertMyEnum() { assertEquals(hyphenateEnumConverter.convert("TrendBreaker"), MyEnum.TrendBreaker); assertEquals(hyphenateEnumConverter.convert("trend-breaker"), MyEnum.TrendBreaker); assertEquals(hyphenateEnumConverter.convert("MAKING_LifeDifficult"), MyEnum.MAKING_LifeDifficult); - //assertEquals(hyphenateEnumConverter.convert("making-life-difficult"), MyEnum.MAKING_LifeDifficult); + assertEquals(hyphenateEnumConverter.convert("making-life-difficult"), MyEnum.MAKING_LifeDifficult); } @Test @@ -101,7 +101,7 @@ public void convertMyOtherEnum() { assertEquals(hyphenateEnumConverter.convert("makingLifeDifficult"), MyOtherEnum.makingLifeDifficult); assertEquals(hyphenateEnumConverter.convert("making-life-difficult"), MyOtherEnum.makingLifeDifficult); assertEquals(hyphenateEnumConverter.convert("READ__UNCOMMITTED"), MyOtherEnum.READ__UNCOMMITTED); - //assertEquals(hyphenateEnumConverter.convert("read-uncommitted"), MyOtherEnum.READ__UNCOMMITTED); + assertEquals(hyphenateEnumConverter.convert("read-uncommitted"), MyOtherEnum.READ__UNCOMMITTED); } @Test @@ -111,7 +111,7 @@ public void testIllegalEnumConfigUtilConversion() { () -> hyphenateEnumConverter.convert("READUNCOMMITTED")); assertEquals( "SRCFG00049: Cannot convert READUNCOMMITTED to enum class io.smallrye.config.ImplicitConverterTest$MyEnum, " + - "allowed values: trend-breaker,discard,making-l-ife-difficult,sigusr1,read-uncommitted,a-b", + "allowed values: trend-breaker,making-life-difficult,discard,sigusr1,read-uncommitted,a-b", exception.getMessage()); }