All Downloads are FREE. Search and download functionalities are using the official Maven repository.

me.alidg.errors.message.TemplateParser Maven / Gradle / Ivy

package me.alidg.errors.message;

import me.alidg.errors.Argument;

import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Responsible for parsing string templates and replacing the named or positional arguments
 * with their corresponding values. The parser treats { and } characters as the variable delimiters.
 *
 * 

Named Arguments

* When the parser sees a templated expression, first it considers that expression as a named argument, even * if it looks like a positional one, e.g. {0}. If it could find an argument matching with that template name, * it would replace the placeholder with its corresponding argument value. For example, the following expression: *
 *     Your age should be at least {minAge} but you're {invalid} years old.
 * 
* Would be translated to the following text when {@code minAge=18} and {@code invalid 17}: *
 *     Your age should be at least 18 but you're 17 years old.
 * 
* *

Positional Arguments

* If template parser couldn't find a matched argument name for any given placeholder, then it will try positional * arguments iff the placeholder is an integer. For example, the following template message: *
 *     The minimum age is {0}
 * 
* When there is no named argument for code {@code 0}, the first argument will replace the {0} placeholder: *
 *     The minimum age is 18
 * 
* *

Escape Character

* If we need to use delimiting characters in a plain text, we can escape them using a backslash. For example, the * following text does not contain any placeholder: *
 *     Plain \{text}
 * 
* *

Placeholders with No Values

* When there is no corresponding value for a placeholder, the placeholder would remain intact. For example, * if there is no corresponding value for {min}, then the placeholder would be in the final outcome. * * @author Ali Dehghani */ final class TemplateParser { /** * A regex to find all '{...}' patterns which are not escaped with a backslash. */ private final Pattern pattern = Pattern.compile("(?Please note that we had to use the thread-safe {@link StringBuffer} here because the * {@link Matcher#appendReplacement(StringBuffer, String)} API needs it. But because JVM elides unnecessary * locks, there shouldn't be any performance issue. * * @param template The templated string to parse. * @param arguments The arguments source to read placeholder values from. * @return The final interpolated string. * @see Lock Elision */ String parse(String template, List arguments) { if (template == null || arguments == null || arguments.isEmpty()) return template; Matcher matcher = pattern.matcher(template); StringBuffer sb = new StringBuffer(); while (matcher.find()) { String placeholder = matcher.group(); Object value = extractValue(placeholder, arguments); if (value != null) matcher.appendReplacement(sb, value.toString()); } matcher.appendTail(sb); return sb.toString().replace("\\{", "{").replace("\\}", "}"); } private Object extractValue(String placeholder, List arguments) { String variable = getPlaceholderVariable(placeholder); // Tries to resolve it as a named argument Optional argument = arguments.stream().filter(a -> a.getName().equals(variable)).findFirst(); if (argument.isPresent()) return argument.map(this::argumentValue).get(); // Otherwise, tries to resolve it as a positional argument try { int index = Integer.parseInt(variable); return argumentValue(arguments.get(index)); } catch (Exception ignored) { } return null; } /** * Extracts the placeholder variable by removing the delimiters. * * @param placeholder The placeholder in {...} format. * @return The extracted variable name. */ private String getPlaceholderVariable(String placeholder) { return placeholder.substring(1, placeholder.length() - 1); } private Object argumentValue(Argument argument) { Object value = argument.getValue(); return value == null ? "null" : value; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy