Reputation: 18455
I want to create a String using a format, replacing some tokens in the format with properties from a bean. Is there a library that supports this or am I going to have to create my own implementation?
Let me demonstate with an example. Say I have a bean Person
;
public class Person {
private String id;
private String name;
private String age;
//getters and setters
}
I want to be able to specify format strings something like;
"{name} is {age} years old."
"Person id {id} is called {name}."
and automatically populate the format placeholders with values from the bean, something like;
String format = "{name} is {age} old."
Person p = new Person(1, "Fred", "32 years");
String formatted = doFormat(format, person); //returns "Fred is 32 years old."
I've had a look at MessageFormat
but this only seems to allow me to pass numeric indexes, not bean properties.
Upvotes: 7
Views: 3358
Reputation: 18455
Rolled my own, testing now. Comments welcome.
import java.lang.reflect.Field;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class BeanFormatter<E> {
private Matcher matcher;
private static final Pattern pattern = Pattern.compile("\\{(.+?)\\}");
public BeanFormatter(String formatString) {
this.matcher = pattern.matcher(formatString);
}
public String format(E bean) throws Exception {
StringBuffer buffer = new StringBuffer();
try {
matcher.reset();
while (matcher.find()) {
String token = matcher.group(1);
String value = getProperty(bean, token);
matcher.appendReplacement(buffer, value);
}
matcher.appendTail(buffer);
} catch (Exception ex) {
throw new Exception("Error formatting bean " + bean.getClass() + " with format " + matcher.pattern().toString(), ex);
}
return buffer.toString();
}
private String getProperty(E bean, String token) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
Field field = bean.getClass().getDeclaredField(token);
field.setAccessible(true);
return String.valueOf(field.get(bean));
}
public static void main(String[] args) throws Exception {
String format = "{name} is {age} old.";
Person p = new Person("Fred", "32 years", 1);
BeanFormatter<Person> bf = new BeanFormatter<Person>(format);
String s = bf.format(p);
System.out.println(s);
}
}
Upvotes: 4
Reputation: 309
Not quite close, but you can look at StringTemplate, your bean:
public static class User {
public int id; // template can directly access via u.id
private String name; // template can't access this
public User(int id, String name) { this.id = id; this.name = name; }
public boolean isManager() { return true; } // u.manager
public boolean hasParkingSpot() { return true; } // u.parkingSpot
public String getName() { return name; } // u.name
public String toString() { return id+":"+name; } // u
}
Then you can render it like this:
ST st = new ST("<b>$u.id$</b>: $u.name$", '$', '$');
st.add("u", new User(999, "parrt"));
String result = st.render(); // "<b>999</b>: parrt"
Code sample above taken from ST4 Introduction
Upvotes: 0
Reputation: 7858
Don't really know how complex is the model you're up to consume but if you want to deal with object trees I would implement my own formatter using Jexl as expession language this way:
The good thing about Jexl is that it will allow you to use method calls, not just properties.
Hope it helps.
Upvotes: 0
Reputation: 64640
Yes, it's possible using the Pojomatic library. Implement and plug in your own implementation of PojoFormatter
. Pojomator#doToString(T)
may be also interesting.
Upvotes: 1