How to replace a placeholder in String with a SimpleDateFormat template

In a given line such as

".../uploads/${customer}/${dateTime('yyyyMMdd')}/report.pdf" 

I need to replace the customer label and yyyyMMdd .

To replace the customer placeholder, I could use the StrSubstitutor from Apache Commons. But how to replace SimpleDateFormat ? We work in a Spring environment, so maybe Spring EL is an option?

The markup for placeholders is not fixed, this is fine if another library needs syntactic changes.

These little tests show the problem:

 SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd"); String template = ".../uploads/${customer}/${dateTime('yyyyMMdd')}/report.pdf"; @Test public void shouldResolvePlaceholder() { final Map<String, String> model = new HashMap<String, String>(); model.put("customer", "Mr. Foobar"); final String filledTemplate = StrSubstitutor.replace(this.template, model); assertEquals(".../uploads/Mr. Foobar/" + this.formatter.format(new Date()) + "/report.pdf", filledTemplate); } 
+8
java spring-el apache-commons
source share
2 answers

Why don't you use MessageFormat ?

 String result = MessageFormat.format(".../uploads/{0}/{1,date,yyyyMMdd}/report.pdf", customer, date); 

Or with String.format

 String result = String.format(".../uploads/%1$s/%2$tY%2$tm%2$td/report.pdf", customer, date); 
+24
source share

Because NilsH suggested that MessageFormat is really good for this purpose. To have named variables, you can hide MessageFormat behind your class:

 public class FormattedStrSubstitutor { public static String formatReplace(Object source, Map<String, String> valueMap) { for (Map.Entry<String, String> entry : valueMap.entrySet()) { String val = entry.getValue(); if (isPlaceholder(val)) { val = getPlaceholderValue(val); String newValue = reformat(val); entry.setValue(newValue); } } return new StrSubstitutor(valueMap).replace(source); } private static boolean isPlaceholder(String isPlaceholder) { return isPlaceholder.startsWith("${"); } private static String getPlaceholderValue(String val) { return val.substring(2, val.length()-1); } private static String reformat(String format) { String result = MessageFormat.format("{0,date," + format + "}", new Date()); return result; } } 

And you should set up your test file:

 SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd"); String template = ".../uploads/${customer}/${dateTime}/report.pdf"; @Test public void shouldResolvePlaceholder() { final Map<String, String> model = new HashMap<String, String>(); model.put("customer", "Mr. Foobar"); model.put("dateTime", "${yyyyMMdd}"); final String filledTemplate = FormattedStrSubstitutor.formatReplace(this.template, model); assertEquals(".../uploads/Mr. Foobar/" + this.formatter.format(new Date()) + "/report.pdf", filledTemplate); } 

I removed generics and replaced them with String. Also, isPlaceholder and getPlaceholderValue hard-coded and expect $ {value} syntax.

But it is just an idea to solve your problem. You can use the methods from StrSubstitutor (just use is or make FormattedStrSubstitutor extends StrSubstitutor ).

You can also use, for example, $ d {value} to format the date and $ foo {value} to format foo.

UPDATE

Cannot sleep without a complete solution. You can add this method to the FormattedStrSubstitutor class:

 public static String replace(Object source, Map<String, String> valueMap) { String staticResolved = new StrSubstitutor(valueMap).replace(source); Pattern p = Pattern.compile("(\\$\\{date)(.*?)(\\})"); Matcher m = p.matcher(staticResolved); String dynamicResolved = staticResolved; while (m.find()) { String result = MessageFormat.format("{0,date" + m.group(2) + "}", new Date()); dynamicResolved = dynamicResolved.replace(m.group(), result); } return dynamicResolved; } 

Your test case is similar to your question (small changes in the placeholder):

 SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd"); String template = ".../uploads/${customer}/${date,yyyyMMdd}/report.pdf"; @Test public void shouldResolvePlaceholder() { final Map<String, String> model = new HashMap<String, String>(); model.put("customer", "Mr. Foobar"); final String filledTemplate = FormattedStrSubstitutor.replace(this.template, model); assertEquals( ".../uploads/Mr. Foobar/" + this.formatter.format(new Date()) + "/report.pdf", filledTemplate); } 

The same restriction as before; no generics and no fix for prefix and suffix for placeholder.

+8
source share

All Articles