This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/master by this push:
     new 0265bad23a StringFormatter class
0265bad23a is described below

commit 0265bad23a4f535a21115528ae0845be09b2e732
Author: James Bognar <[email protected]>
AuthorDate: Fri Nov 28 10:38:30 2025 -0500

    StringFormatter class
---
 .../apache/juneau/common/utils/StringUtils.java    | 104 +++++++++++----------
 .../java/org/apache/juneau/common/utils/Utils.java |  50 ++++++++--
 .../src/main/java/org/apache/juneau/BeanMap.java   |   2 +-
 .../main/java/org/apache/juneau/cp/Messages.java   |   2 +-
 .../apache/juneau/rest/mock/MockPathResolver.java  |   2 +-
 .../juneau/common/utils/StringUtils_Test.java      |  72 +++++++-------
 6 files changed, 137 insertions(+), 95 deletions(-)

diff --git 
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/StringUtils.java
 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/StringUtils.java
index ac5306f369..b296307fbd 100644
--- 
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/StringUtils.java
+++ 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/StringUtils.java
@@ -734,6 +734,12 @@ public class StringUtils {
         * to allow proper formatting. For simple placeholders (e.g., {@code 
{0}}), arguments are converted to
         * readable strings using {@link #convertToReadable(Object)}.
         *
+        * <p>
+        * Supports standard MessageFormat placeholders: <js>"{0}"</js>, 
<js>"{1,number}"</js>, <js>"{2,date}"</js>, etc.
+        * Also supports un-numbered placeholders: <js>"{}"</js> - Sequential 
placeholders that are automatically numbered.
+        * Note: For un-numbered placeholders, use {@link #format(String, 
Object...)} instead, as this method uses
+        * standard {@link MessageFormat} which requires explicit indices.
+        *
         * @param pattern The string pattern.
         * @param args The arguments.
         * @return The formatted string.
@@ -764,17 +770,22 @@ public class StringUtils {
        }
 
        /**
-        * Formats a string using printf-style format specifiers.
+        * Formats a string using printf-style and/or MessageFormat-style 
format specifiers.
         *
         * <p>
-        * This method provides printf-style formatting similar to C's 
<c>printf()</c> function and Java's
-        * {@link String#format(String, Object...)}. It uses the same format 
specifier syntax.
+        * This method provides unified string formatting that supports both 
printf-style formatting
+        * (similar to C's <c>printf()</c> function and Java's {@link 
String#format(String, Object...)})
+        * and MessageFormat-style formatting in the same pattern.
         *
-        * <p>
-        * This is the primary formatting method using printf-style syntax 
(e.g., <js>"%s"</js>, <js>"%d"</js>, <js>"%f"</js>).
-        * For MessageFormat-style formatting, use {@link #mformat(String, 
Object...)}.
+        * <h5 class='section'>Format Support:</h5>
+        * <ul>
+        *   <li><b>Printf-style:</b> <js>"%s"</js>, <js>"%d"</js>, 
<js>"%.2f"</js>, <js>"%1$s"</js>, etc.</li>
+        *   <li><b>MessageFormat-style:</b> <js>"{0}"</js>, 
<js>"{1,number}"</js>, <js>"{2,date}"</js>, etc.</li>
+        *   <li><b>Un-numbered MessageFormat:</b> <js>"{}"</js> - Sequential 
placeholders that are automatically numbered</li>
+        *   <li><b>Mixed formats:</b> Both styles can be used in the same 
pattern</li>
+        * </ul>
         *
-        * <h5 class='section'>Format Specifiers:</h5>
+        * <h5 class='section'>Printf Format Specifiers:</h5>
         * <ul>
         *   <li><b>%s</b> - String</li>
         *   <li><b>%d</b> - Decimal integer</li>
@@ -794,12 +805,15 @@ public class StringUtils {
         *
         * <h5 class='section'>Format Specifier Syntax:</h5>
         * <p>
-        * Format specifiers follow this pattern: 
<c>%[argument_index$][flags][width][.precision]conversion</c>
+        * Printf format specifiers follow this pattern: 
<c>%[argument_index$][flags][width][.precision]conversion</c>
+        * </p>
+        * <p>
+        * MessageFormat placeholders follow this pattern: 
<c>{argument_index[,format_type[,format_style]]}</c>
         * </p>
         *
         * <h5 class='section'>Examples:</h5>
         * <p class='bjava'>
-        *      <jc>// Basic string and number formatting</jc>
+        *      <jc>// Printf-style formatting</jc>
         *      format(<js>"Hello %s, you have %d items"</js>, <js>"John"</js>, 
5);
         *      <jc>// Returns: "Hello John, you have 5 items"</jc>
         *
@@ -807,29 +821,42 @@ public class StringUtils {
         *      format(<js>"Price: $%.2f"</js>, 19.99);
         *      <jc>// Returns: "Price: $19.99"</jc>
         *
-        *      <jc>// Width and alignment</jc>
+        *      <jc>// MessageFormat-style formatting</jc>
+        *      format(<js>"Hello {0}, you have {1} items"</js>, 
<js>"John"</js>, 5);
+        *      <jc>// Returns: "Hello John, you have 5 items"</jc>
+        *
+        *      <jc>// Un-numbered MessageFormat placeholders (sequential)</jc>
+        *      format(<js>"Hello {}, you have {} items"</js>, <js>"John"</js>, 
5);
+        *      <jc>// Returns: "Hello John, you have 5 items"</jc>
+        *
+        *      <jc>// Mixed format styles in the same pattern</jc>
+        *      format(<js>"User {0} has %d items and %s status"</js>, 
<js>"Alice"</js>, 10, <js>"active"</js>);
+        *      <jc>// Returns: "User Alice has 10 items and active status"</jc>
+        *
+        *      <jc>// Width and alignment (printf)</jc>
         *      format(<js>"Name: %-20s Age: %3d"</js>, <js>"John"</js>, 25);
         *      <jc>// Returns: "Name: John                 Age:  25"</jc>
         *
-        *      <jc>// Hexadecimal</jc>
+        *      <jc>// Hexadecimal (printf)</jc>
         *      format(<js>"Color: #%06X"</js>, 0xFF5733);
         *      <jc>// Returns: "Color: #FF5733"</jc>
         *
-        *      <jc>// Scientific notation</jc>
-        *      format(<js>"Value: %.2e"</js>, 1234567.0);
-        *      <jc>// Returns: "Value: 1.23e+06"</jc>
-        *
         *      <jc>// Argument index (reuse arguments)</jc>
-        *      format(<js>"%1$s loves %2$s, and %1$s also loves %3$s"</js>, 
<js>"Alice"</js>, <js>"Bob"</js>, <js>"Charlie"</js>);
+        *      format(<js>"%1$s loves %2$s, and {0} also loves %3$s"</js>, 
<js>"Alice"</js>, <js>"Bob"</js>, <js>"Charlie"</js>);
         *      <jc>// Returns: "Alice loves Bob, and Alice also loves 
Charlie"</jc>
         * </p>
         *
         * <h5 class='section'>Comparison with mformat():</h5>
+        * <p>
+        * This method supports both formats, while {@link #mformat(String, 
Object...)} only supports MessageFormat-style.
+        * </p>
         * <p class='bjava'>
-        *      <jc>// Printf style (this method)</jc>
+        *      <jc>// Both styles supported (this method)</jc>
         *      format(<js>"Hello %s, you have %d items"</js>, <js>"John"</js>, 
5);
+        *      format(<js>"Hello {0}, you have {1} items"</js>, 
<js>"John"</js>, 5);
+        *      format(<js>"User {0} has %d items"</js>, <js>"Alice"</js>, 10);
         *
-        *      <jc>// MessageFormat style</jc>
+        *      <jc>// MessageFormat style only</jc>
         *      mformat(<js>"Hello {0}, you have {1} items"</js>, 
<js>"John"</js>, 5);
         * </p>
         *
@@ -839,12 +866,13 @@ public class StringUtils {
         * or cause a {@link NullPointerException} for numeric conversions 
(consistent with {@link String#format(String, Object...)}).
         * </p>
         *
-        * @param pattern The printf-style format string.
+        * @param pattern The format string supporting both MessageFormat and 
printf-style placeholders.
         * @param args The arguments to format.
         * @return The formatted string.
         * @throws java.util.IllegalFormatException If the format string is 
invalid or arguments don't match the format specifiers.
+        * @see StringFormat for detailed format specification
         * @see String#format(String, Object...)
-        * @see #mformat(String, Object...) for MessageFormat-style formatting
+        * @see #mformat(String, Object...) for MessageFormat-only formatting
         */
        public static String format(String pattern, Object...args) {
                return StringFormat.format(pattern, args);
@@ -2490,32 +2518,6 @@ public class StringUtils {
                return count;
        }
 
-       /**
-        * Formats a string template with named arguments using 
<js>"{name}"</js> placeholders.
-        *
-        * <p>
-        * Similar to {@link #replaceVars(String, Map)} but designed for 
formatting scenarios.
-        * Replaces placeholders of the form <js>"{name}"</js> with values from 
the map.
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bjava'>
-        *      var args = Map.of(<js>"name"</js>, <js>"John"</js>, 
<js>"age"</js>, <js>30</js>);
-        *      formatWithNamedArgs(<js>"Hello {name}, you are {age} years 
old"</js>, args);
-        *      <jc>// Returns: "Hello John, you are 30 years old"</jc>
-        * </p>
-        *
-        * @param template The template string with <js>"{name}"</js> 
placeholders.
-        * @param args The map containing the named argument values.
-        * @return The formatted string with placeholders replaced, or the 
original template if args is null or empty.
-        */
-       public static String formatWithNamedArgs(String template, 
Map<String,Object> args) {
-               if (template == null)
-                       return null;
-               if (args == null || args.isEmpty())
-                       return template;
-               return replaceVars(template, args);
-       }
-
        /**
         * Interpolates variables in a template string using <js>"${name}"</js> 
syntax.
         *
@@ -4312,6 +4314,10 @@ public class StringUtils {
         * Simple utility for replacing variables of the form <js>"{key}"</js> 
with values in the specified map.
         *
         * <p>
+        * Supports named MessageFormat-style variables: <js>"{key}"</js> where 
<c>key</c> is a map key.
+        * For un-numbered sequential placeholders <js>"{}"</js>, use {@link 
#format(String, Object...)} instead.
+        *
+        * <p>
         * Nested variables are supported in both the input string and map 
values.
         *
         * <p>
@@ -4324,7 +4330,7 @@ public class StringUtils {
         * @param m The map containing the variable values.
         * @return The new string with variables replaced, or the original 
string if it didn't have variables in it.
         */
-       public static String replaceVars(String s, Map<String,Object> m) {
+       public static String formatNamed(String s, Map<String,Object> m) {
 
                if (s == null)
                        return null;
@@ -4360,7 +4366,7 @@ public class StringUtils {
                                                depth--;
                                        } else {
                                                var key = s.substring(x + 1, i);
-                                               key = (hasInternalVar ? 
replaceVars(key, m) : key);
+                                               key = (hasInternalVar ? 
formatNamed(key, m) : key);
                                                hasInternalVar = false;
                                                // JUNEAU-248: Check if key 
exists in map by attempting to get it
                                                // For regular maps: use 
containsKey() OR nn(get()) check
@@ -4377,7 +4383,7 @@ public class StringUtils {
                                                        var v = val.toString();
                                                        // If the replacement 
also contains variables, replace them now.
                                                        if (v.indexOf('{') != 
-1)
-                                                               v = 
replaceVars(v, m);
+                                                               v = 
formatNamed(v, m);
                                                        out.append(v);
                                                }
                                                state = S1;
diff --git 
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/Utils.java
 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/Utils.java
index d94a6fc1fe..3a10862138 100644
--- 
a/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/Utils.java
+++ 
b/juneau-core/juneau-common/src/main/java/org/apache/juneau/common/utils/Utils.java
@@ -372,36 +372,64 @@ public class Utils {
         * Shortcut for calling {@link StringUtils#format(String, Object...)}.
         *
         * <p>
-        * This method provides a convenient shorthand for printf-style string 
formatting.
+        * This method provides a convenient shorthand for string formatting 
that supports both
+        * MessageFormat-style and printf-style formatting in the same pattern.
+        *
+        * <h5 class='section'>Format Support:</h5>
+        * <ul>
+        *   <li><b>Printf-style:</b> <js>"%s"</js>, <js>"%d"</js>, 
<js>"%.2f"</js>, <js>"%1$s"</js>, etc.</li>
+        *   <li><b>MessageFormat-style:</b> <js>"{0}"</js>, 
<js>"{1,number}"</js>, <js>"{2,date}"</js>, etc.</li>
+        *   <li><b>Un-numbered MessageFormat:</b> <js>"{}"</js> - Sequential 
placeholders that are automatically numbered</li>
+        *   <li><b>Mixed formats:</b> Both styles can be used in the same 
pattern</li>
+        * </ul>
         *
         * <h5 class='section'>Examples:</h5>
         * <p class='bjava'>
-        *      <jc>// Basic formatting</jc>
+        *      <jc>// Printf-style formatting</jc>
         *      f(<js>"Hello %s, you have %d items"</js>, <js>"John"</js>, 5);
         *      <jc>// Returns: "Hello John, you have 5 items"</jc>
         *
         *      <jc>// Floating point</jc>
         *      f(<js>"Price: $%.2f"</js>, 19.99);
         *      <jc>// Returns: "Price: $19.99"</jc>
+        *
+        *      <jc>// MessageFormat-style formatting</jc>
+        *      f(<js>"Hello {0}, you have {1} items"</js>, <js>"John"</js>, 5);
+        *      <jc>// Returns: "Hello John, you have 5 items"</jc>
+        *
+        *      <jc>// Un-numbered MessageFormat placeholders (sequential)</jc>
+        *      f(<js>"Hello {}, you have {} items"</js>, <js>"John"</js>, 5);
+        *      <jc>// Returns: "Hello John, you have 5 items"</jc>
+        *
+        *      <jc>// Mixed format styles in the same pattern</jc>
+        *      f(<js>"User {0} has %d items and %s status"</js>, 
<js>"Alice"</js>, 10, <js>"active"</js>);
+        *      <jc>// Returns: "User Alice has 10 items and active status"</jc>
         * </p>
         *
-        * @param pattern The printf-style format string.
+        * @param pattern The format string supporting both MessageFormat and 
printf-style placeholders.
         * @param args The arguments to format.
         * @return The formatted string.
         * @see StringUtils#format(String, Object...)
-        * @see #mf(String, Object...) for MessageFormat-style formatting
+        * @see StringFormat for detailed format specification
+        * @see #mf(String, Object...) for MessageFormat-only formatting
         */
        public static String f(String pattern, Object...args) {
                return format(pattern, args);
        }
 
        /**
-        * Creates a formatted string supplier with printf-style format 
arguments for lazy evaluation.
+        * Creates a formatted string supplier with format arguments for lazy 
evaluation.
         *
         * <p>This method returns a {@link Supplier} that formats the string 
pattern with the provided arguments
         * only when the supplier's {@code get()} method is called. This is 
useful for expensive string formatting
         * operations that may not always be needed, such as error messages in 
assertions.</p>
         *
+        * <p>
+        * Supports both MessageFormat-style and printf-style formatting in the 
same pattern.
+        * Also supports un-numbered MessageFormat placeholders: <js>"{}"</js> 
- Sequential placeholders that are automatically numbered.
+        * See {@link #f(String, Object...)} for format specification details.
+        * </p>
+        *
         * <h5 class='section'>Usage Examples:</h5>
         * <p class='bjava'>
         *      <jc>// Lazy evaluation - string is only formatted if assertion 
fails</jc>
@@ -409,13 +437,21 @@ public class Utils {
         *
         *      <jc>// Can be used anywhere a Supplier&lt;String&gt; is 
expected</jc>
         *      Supplier&lt;String&gt; <jv>messageSupplier</jv> = 
fs(<js>"Processing item %d of %d"</js>, i, total);
+        *
+        *      <jc>// Mixed format styles</jc>
+        *      Supplier&lt;String&gt; <jv>msg</jv> = fs(<js>"User {0} has %d 
items"</js>, <js>"Alice"</js>, 10);
+        *
+        *      <jc>// Un-numbered MessageFormat placeholders</jc>
+        *      Supplier&lt;String&gt; <jv>msg2</jv> = fs(<js>"Hello {}, you 
have {} items"</js>, <js>"John"</js>, 5);
         * </p>
         *
-        * @param pattern The printf-style format string using <js>%s</js>, 
<js>%d</js>, etc. placeholders.
+        * @param pattern The format string supporting both MessageFormat and 
printf-style placeholders
+        *      (e.g., <js>"{0}"</js>, <js>"%s"</js>, <js>"%d"</js>, etc.).
         * @param args The arguments to substitute into the pattern 
placeholders.
         * @return A {@link Supplier} that will format the string when {@code 
get()} is called.
         * @see StringUtils#format(String, Object...)
-        * @see #mfs(String, Object...) for MessageFormat-style formatting
+        * @see #f(String, Object...) for format specification details
+        * @see #mfs(String, Object...) for MessageFormat-only formatting
         */
        public static Supplier<String> fs(String pattern, Object...args) {
                return () -> format(pattern, args);
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMap.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMap.java
index 9d4c8faed4..b0c04605db 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMap.java
@@ -650,7 +650,7 @@ public class BeanMap<T> extends AbstractMap<String,Object> 
implements Delegate<T
         * @return A new string with variables replaced, or the same string if 
no variables were found.
         */
        public String resolveVars(String s) {
-               return replaceVars(s, this);
+               return formatNamed(s, this);
        }
 
        /**
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/Messages.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/Messages.java
index 343957ac55..1bb254649e 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/Messages.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/Messages.java
@@ -283,7 +283,7 @@ public class Messages extends ResourceBundle {
                        var cl = forClass.getClassLoader();
                        var m = JsonMap.of("name", name, "package", 
forClass.getPackage().getName());
                        for (var bn : baseNames) {
-                               bn = StringUtils.replaceVars(bn, m);
+                               bn = StringUtils.formatNamed(bn, m);
                                var rb = findBundle(bn, locale, cl);
                                if (nn(rb))
                                        return rb;
diff --git 
a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockPathResolver.java
 
b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockPathResolver.java
index 6deb41dc05..17806c79dd 100644
--- 
a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockPathResolver.java
+++ 
b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockPathResolver.java
@@ -37,7 +37,7 @@ import org.apache.juneau.rest.util.*;
 class MockPathResolver {
 
        private static String fixSegment(String s, Map<String,Object> pathVars) 
{
-               s = replaceVars(emptyIfNull(s), pathVars);
+               s = formatNamed(emptyIfNull(s), pathVars);
                if (s.isEmpty() || s.equals("/"))
                        return "";
                s = trimTrailingSlashes(s);
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/common/utils/StringUtils_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/common/utils/StringUtils_Test.java
index 538c864bd8..90cab38646 100755
--- 
a/juneau-utest/src/test/java/org/apache/juneau/common/utils/StringUtils_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/common/utils/StringUtils_Test.java
@@ -262,33 +262,33 @@ class StringUtils_Test extends TestBase {
        void a03_replaceVars() throws Exception {
                var m = 
JsonMap.ofJson("{a:'A',b:1,c:true,d:'{e}',e:'E{f}E',f:'F',g:'{a}',h:'a',i:null}");
 
-               assertEquals("xxx", replaceVars("xxx", m));
-               assertEquals("A", replaceVars("{a}", m));
-               assertEquals("AA", replaceVars("{a}{a}", m));
-               assertEquals("xAx", replaceVars("x{a}x", m));
-               assertEquals("xAxAx", replaceVars("x{a}x{a}x", m));
-               assertEquals("1", replaceVars("{b}", m));
-               assertEquals("11", replaceVars("{b}{b}", m));
-               assertEquals("x1x", replaceVars("x{b}x", m));
-               assertEquals("x1x1x", replaceVars("x{b}x{b}x", m));
-               assertEquals("true", replaceVars("{c}", m));
-               assertEquals("truetrue", replaceVars("{c}{c}", m));
-               assertEquals("xtruextruex", replaceVars("x{c}x{c}x", m));
-               assertEquals("EFE", replaceVars("{d}", m));
-               assertEquals("EFEEFE", replaceVars("{d}{d}", m));
-               assertEquals("xEFEx", replaceVars("x{d}x", m));
-               assertEquals("xEFExEFEx", replaceVars("x{d}x{d}x", m));
-               assertEquals("A", replaceVars("{g}", m));
-               assertEquals("AA", replaceVars("{g}{g}", m));
-               assertEquals("xAx", replaceVars("x{g}x", m));
-               assertEquals("xAxAx", replaceVars("x{g}x{g}x", m));
-               assertEquals("{x}", replaceVars("{x}", m));
-               assertEquals("{x}{x}", replaceVars("{x}{x}", m));
-               assertEquals("x{x}x{x}x", replaceVars("x{x}x{x}x", m));
-               assertEquals("{A}", replaceVars("{{g}}", m));
-               assertEquals("A", replaceVars("{{h}}", m));
-               assertEquals("{}", replaceVars("{{i}}", m));
-               assertEquals("{}", replaceVars("{}", m));
+               assertEquals("xxx", formatNamed("xxx", m));
+               assertEquals("A", formatNamed("{a}", m));
+               assertEquals("AA", formatNamed("{a}{a}", m));
+               assertEquals("xAx", formatNamed("x{a}x", m));
+               assertEquals("xAxAx", formatNamed("x{a}x{a}x", m));
+               assertEquals("1", formatNamed("{b}", m));
+               assertEquals("11", formatNamed("{b}{b}", m));
+               assertEquals("x1x", formatNamed("x{b}x", m));
+               assertEquals("x1x1x", formatNamed("x{b}x{b}x", m));
+               assertEquals("true", formatNamed("{c}", m));
+               assertEquals("truetrue", formatNamed("{c}{c}", m));
+               assertEquals("xtruextruex", formatNamed("x{c}x{c}x", m));
+               assertEquals("EFE", formatNamed("{d}", m));
+               assertEquals("EFEEFE", formatNamed("{d}{d}", m));
+               assertEquals("xEFEx", formatNamed("x{d}x", m));
+               assertEquals("xEFExEFEx", formatNamed("x{d}x{d}x", m));
+               assertEquals("A", formatNamed("{g}", m));
+               assertEquals("AA", formatNamed("{g}{g}", m));
+               assertEquals("xAx", formatNamed("x{g}x", m));
+               assertEquals("xAxAx", formatNamed("x{g}x{g}x", m));
+               assertEquals("{x}", formatNamed("{x}", m));
+               assertEquals("{x}{x}", formatNamed("{x}{x}", m));
+               assertEquals("x{x}x{x}x", formatNamed("x{x}x{x}x", m));
+               assertEquals("{A}", formatNamed("{{g}}", m));
+               assertEquals("A", formatNamed("{{h}}", m));
+               assertEquals("{}", formatNamed("{{i}}", m));
+               assertEquals("{}", formatNamed("{}", m));
        }
 
        
//====================================================================================================
@@ -1450,23 +1450,23 @@ class StringUtils_Test extends TestBase {
        }
 
        @Test
-       void a62_formatWithNamedArgs() {
+       void a62_formatNamed() {
                var args = new HashMap<String,Object>();
                args.put("name", "John");
                args.put("age", 30);
                args.put("city", "New York");
-               assertEquals("Hello John, you are 30 years old", 
formatWithNamedArgs("Hello {name}, you are {age} years old", args));
-               assertEquals("Welcome to New York", 
formatWithNamedArgs("Welcome to {city}", args));
-               assertEquals("Hello {unknown}", formatWithNamedArgs("Hello 
{unknown}", args)); // Unknown placeholder kept
-               assertEquals("No placeholders", formatWithNamedArgs("No 
placeholders", args));
-               assertNull(formatWithNamedArgs(null, args));
-               assertEquals("Template", formatWithNamedArgs("Template", null));
-               assertEquals("Template", formatWithNamedArgs("Template", new 
HashMap<>()));
+               assertEquals("Hello John, you are 30 years old", 
formatNamed("Hello {name}, you are {age} years old", args));
+               assertEquals("Welcome to New York", formatNamed("Welcome to 
{city}", args));
+               assertEquals("Hello {unknown}", formatNamed("Hello {unknown}", 
args)); // Unknown placeholder kept
+               assertEquals("No placeholders", formatNamed("No placeholders", 
args));
+               assertNull(formatNamed(null, args));
+               assertEquals("Template", formatNamed("Template", null));
+               assertEquals("Template", formatNamed("Template", new 
HashMap<>()));
                // Test with null values
                var argsWithNull = new HashMap<String,Object>();
                argsWithNull.put("name", "John");
                argsWithNull.put("value", null);
-               assertEquals("Hello John, value: ", formatWithNamedArgs("Hello 
{name}, value: {value}", argsWithNull));
+               assertEquals("Hello John, value: ", formatNamed("Hello {name}, 
value: {value}", argsWithNull));
        }
 
        
//====================================================================================================

Reply via email to