String replacement in java, similar to a velocity template

JavaStringReflectionVelocity

Java Problem Overview


Is there any String replacement mechanism in Java, where I can pass objects with a text, and it replaces the string as it occurs.
For example, the text is :

Hello ${user.name},
    Welcome to ${site.name}. 

The objects I have are "user" and "site". I want to replace the strings given inside ${} with its equivalent values from the objects. This is same as we replace objects in a velocity template.

Java Solutions


Solution 1 - Java

Use StringSubstitutor from Apache Commons Text.

https://commons.apache.org/proper/commons-text/

It will do it for you (and its open source...)

 Map<String, String> valuesMap = new HashMap<String, String>();
 valuesMap.put("animal", "quick brown fox");
 valuesMap.put("target", "lazy dog");
 String templateString = "The ${animal} jumped over the ${target}.";
 StringSubstitutor sub = new StringSubstitutor(valuesMap);
 String resolvedString = sub.replace(templateString);

Solution 2 - Java

Take a look at the java.text.MessageFormat class, MessageFormat takes a set of objects, formats them, then inserts the formatted strings into the pattern at the appropriate places.

Object[] params = new Object[]{"hello", "!"};
String msg = MessageFormat.format("{0} world {1}", params);

Solution 3 - Java

My preferred way is String.format() because its a oneliner and doesn't require third party libraries:

String message = String.format("Hello! My name is %s, I'm %s.", name, age); 

I use this regularly, e.g. in exception messages like:

throw new Exception(String.format("Unable to login with email: %s", email));

Hint: You can put in as many variables as you like because format() uses Varargs

Solution 4 - Java

I threw together a small test implementation of this. The basic idea is to call format and pass in the format string, and a map of objects, and the names that they have locally.

The output of the following is:

> My dog is named fido, and Jane Doe owns him.

public class StringFormatter {

    private static final String fieldStart = "\\$\\{";
    private static final String fieldEnd = "\\}";

    private static final String regex = fieldStart + "([^}]+)" + fieldEnd;
    private static final Pattern pattern = Pattern.compile(regex);

    public static String format(String format, Map<String, Object> objects) {
        Matcher m = pattern.matcher(format);
        String result = format;
        while (m.find()) {
            String[] found = m.group(1).split("\\.");
            Object o = objects.get(found[0]);
            Field f = o.getClass().getField(found[1]);
            String newVal = f.get(o).toString();
            result = result.replaceFirst(regex, newVal);
        }
        return result;
    }

    static class Dog {
        public String name;
        public String owner;
        public String gender;
    }

    public static void main(String[] args) {
        Dog d = new Dog();
        d.name = "fido";
        d.owner = "Jane Doe";
        d.gender = "him";
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("d", d);
        System.out.println(
           StringFormatter.format(
                "My dog is named ${d.name}, and ${d.owner} owns ${d.gender}.", 
                map));
    }
}

Note: This doesn't compile due to unhandled exceptions. But it makes the code much easier to read.

Also, I don't like that you have to construct the map yourself in the code, but I don't know how to get the names of the local variables programatically. The best way to do it, is to remember to put the object in the map as soon as you create it.

The following example produces the results that you want from your example:

public static void main(String[] args) {
    Map<String, Object> map = new HashMap<String, Object>();
    Site site = new Site();
    map.put("site", site);
    site.name = "StackOverflow.com";
    User user = new User();
    map.put("user", user);
    user.name = "jjnguy";
    System.out.println(
         format("Hello ${user.name},\n\tWelcome to ${site.name}. ", map));
}

I should also mention that I have no idea what Velocity is, so I hope this answer is relevant.

Solution 5 - Java

Here's an outline of how you could go about doing this. It should be relatively straightforward to implement it as actual code.

  1. Create a map of all the objects that will be referenced in the template.
  2. Use a regular expression to find variable references in the template and replace them with their values (see step 3). The Matcher class will come in handy for find-and-replace.
  3. Split the variable name at the dot. user.name would become user and name. Look up user in your map to get the object and use reflection to obtain the value of name from the object. Assuming your objects have standard getters, you will look for a method getName and invoke it.

Solution 6 - Java

There are a couple of Expression Language implementations out there that does this for you, could be preferable to using your own implementation as or if your requirments grow, see for example JUEL and MVEL

I like and have successfully used MVEL in at least one project.

Also see the Stackflow post JSTL/JSP EL (Expression Language) in a non JSP (standalone) context

Solution 7 - Java

I created this utility that uses vanilla Java. It combines two formats... {} and %s style from String.format.... into one method call. Please note it only replaces empty {} brackets, not {someWord}.

public class LogUtils {

    public static String populate(String log, Object... objects) {
        log = log.replaceAll("\\{\\}", "%s");
        return String.format(log, objects);
    }

    public static void main(String[] args) {
        System.out.println(populate("x = %s, y ={}", 5, 4));;
    }

}

Solution 8 - Java

Handlebars.java might be a better option in terms of a Velocity-like syntax with other server-side templating features.

http://jknack.github.io/handlebars.java/

Handlebars handlebars = new Handlebars();
Template template = handlebars.compileInline("Hello {{this}}!");
System.out.println(template.apply("Handlebars.java"));

Solution 9 - Java

There is nothing out of the box that is comparable to velocity since velocity was written to solve exactly that problem. The closest thing you can try is looking into the Formatter

http://cupi2.uniandes.edu.co/site/images/recursos/javadoc/j2se/1.5.0/docs/api/java/util/Formatter.html

However the formatter as far as I know was created to provide C like formatting options in Java so it may not scratch exactly your itch but you are welcome to try :).

Solution 10 - Java

I use GroovyShell in java to parse template with Groovy GString:

Binding binding = new Binding();
GroovyShell gs = new GroovyShell(binding);
// this JSONObject can also be replaced by any Java Object
JSONObject obj = new JSONObject();
obj.put("key", "value");
binding.setProperty("obj", obj)
String str = "${obj.key}";
String exp = String.format("\"%s\".toString()", str);
String res = (String) gs.evaluate(exp);
// value
System.out.println(str);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJoeView Question on Stackoverflow
Solution 1 - JavaJH.View Answer on Stackoverflow
Solution 2 - JavaRealHowToView Answer on Stackoverflow
Solution 3 - JavaartgroheView Answer on Stackoverflow
Solution 4 - JavajjnguyView Answer on Stackoverflow
Solution 5 - JavacasablancaView Answer on Stackoverflow
Solution 6 - JavaChristoffer SoopView Answer on Stackoverflow
Solution 7 - JavaJose MartinezView Answer on Stackoverflow
Solution 8 - JavaAdam WiseView Answer on Stackoverflow
Solution 9 - JavaMike MilkinView Answer on Stackoverflow
Solution 10 - JavaKanView Answer on Stackoverflow