What is the best way to create Velocity Template from a String?
I'm aware of Velocity.evaluate method where I can pass String or StringReader, but I'm curios is there a better way to do it (e.g. any advantage of creating an instance of Template).
There is some overhead parsing template. You might see some performance gain by pre-parsing the template if your template is large and you use it repeatedly. You can do something like this,
RuntimeServices runtimeServices = RuntimeSingleton.getRuntimeServices();
StringReader reader = new StringReader(bufferForYourTemplate);
Template template = new Template();
template.setRuntimeServices(runtimeServices);
/*
* The following line works for Velocity version up to 1.7
* For version 2, replace "Template name" with the variable, template
*/
template.setData(runtimeServices.parse(reader, "Template name")));
template.initDocument();
Then you can call template.merge() over and over again without parsing it everytime.
BTW, you can pass String directly to Velocity.evaluate().
The above sample code is working for me. It uses Velocity version 1.7 and log4j.
private static void velocityWithStringTemplateExample() {
// Initialize the engine.
VelocityEngine engine = new VelocityEngine();
engine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, "org.apache.velocity.runtime.log.Log4JLogChute");
engine.setProperty("runtime.log.logsystem.log4j.logger", LOGGER.getName());
engine.setProperty(Velocity.RESOURCE_LOADER, "string");
engine.addProperty("string.resource.loader.class", StringResourceLoader.class.getName());
engine.addProperty("string.resource.loader.repository.static", "false");
// engine.addProperty("string.resource.loader.modificationCheckInterval", "1");
engine.init();
// Initialize my template repository. You can replace the "Hello $w" with your String.
StringResourceRepository repo = (StringResourceRepository) engine.getApplicationAttribute(StringResourceLoader.REPOSITORY_NAME_DEFAULT);
repo.putStringResource("woogie2", "Hello $w");
// Set parameters for my template.
VelocityContext context = new VelocityContext();
context.put("w", "world!");
// Get and merge the template with my parameters.
Template template = engine.getTemplate("woogie2");
StringWriter writer = new StringWriter();
template.merge(context, writer);
// Show the result.
System.out.println(writer.toString());
}
A similar so question.
This works in Velocity 2.1
// Initialize the engine
VelocityEngine velocityEngine = new VelocityEngine();
velocityEngine.setProperty(Velocity.RESOURCE_LOADERS, "string");
velocityEngine.setProperty("resource.loader.string.class", StringResourceLoader.class.getName());
velocityEngine.setProperty("resource.loader.string.cache", true);
velocityEngine.setProperty("resource.loader.string.modification_check_interval", 60);
velocityEngine.init();
// Add template to repository
StringResourceRepository repository = StringResourceLoader.getRepository();
repository.putStringResource("hello_world", "Hello $w");
// Set parameters
VelocityContext context = new VelocityContext();
context.put("w", "world!");
// Process the template
StringWriter writer = new StringWriter();
velocityEngine.getTemplate("hello_world").merge( context, writer );
System.out.println(writer.toString());
RuntimeServices rs = RuntimeSingleton.getRuntimeServices();
StringReader sr = new StringReader("Username is $username");
SimpleNode sn = rs.parse(sr, "User Information");
Template t = new Template();
t.setRuntimeServices(rs);
t.setData(sn);
t.initDocument();
VelocityContext vc = new VelocityContext();
vc.put("username", "John");
StringWriter sw = new StringWriter();
t.merge(vc, sw);
System.out.println(sw.toString());
Velocity 2 can be integrated into the JSR223 Java Scripting Language Framework which make another option to transform string as a template:
ScriptEngineManager manager = new ScriptEngineManager();
manager.registerEngineName("velocity", new VelocityScriptEngineFactory());
ScriptEngine engine = manager.getEngineByName("velocity");
System.setProperty(VelocityScriptEngine.VELOCITY_PROPERTIES, "path/to/velocity.properties");
String script = "Hello $world";
Writer writer = new StringWriter();
engine.getContext().setWriter(writer);
Object result = engine.eval(script);
System.out.println(writer);
If you are looking for just variable substitution then following works
public String velocityEvaluate(final String template, final NotificationDTO notificationDTO) {
final Map<String, String> context = getContextMap(notificationDTO);
final VelocityContext velocityContext = new VelocityContext(context);
final StringWriter stringWriter = new StringWriter();
final StringReader reader = new StringReader(template);
Velocity.evaluate(velocityContext, stringWriter, "Velocity String Template Evaluation", reader);
return stringWriter.toString();
}
In case if any one looking to transform from json string to json object, in that case, need to convert json string to JsonNode & store it in context. For Ex:
String jsonDataAsString = "{"name": "Aps"}";
JsonNode nodes = new ObjectMapper().readTree(jsonDataAsString );
VelocityContext velocityContext = new VelocityContext();
velocityContext.put("root", nodes);
then in your template, you can refer originating data which are set as "root" via "$root."+property
$root.name
Hope it helps someone.