Hello World
Follow these steps to create a simple Hello World template and use it in Java:
Download
closure-templates-for-java-latest.zip.This archive contains the following files:
soy-latest.jar— A standalone jar file that contains all the Closure Templates classes and their dependencies.SoyParseInfoGenerator.jar— A standalone executable jar that parses Soy files and generates Java classes that contain information such as template and parameter names. You will use this file later in the Using SoyParseInfoGenerator section.
Put these files in your working directory, for example in:
~/helloworld_java/
All files that contain Closure Templates end with the
.soyfile extension and are called Soy files. Create a file in this directory calledsimple.soyand copy this line to the file:{namespace examples.simple}This line declares a namespace for all the templates that you define in this file.
Copy the following basic template to the file, making sure that it appears after the namespace declaration:
/** * Says hello to the world. */ {template .helloWorld} Hello world! {/template}This template simply outputs the text "
Hello world!". It has the partial name.helloWorld, which, when combined with the namespace, forms the fully qualified template nameexamples.simple.helloWorld.In the same directory as
simple.soy, create a file calledHelloWorld.javaand copy the following contents into the file:import com.google.template.soy.SoyFileSet; import com.google.template.soy.data.SoyMapData; import com.google.template.soy.tofu.SoyTofu; import java.io.File; public class HelloWorld { public static void main (String[] args) { // Bundle the Soy files for your project into a SoyFileSet. SoyFileSet sfs = new SoyFileSet.Builder().add(new File("simple.soy")).build(); // Compile the template into a SoyTofu object. // SoyTofu's newRenderer method returns an object that can render any template in the file set. SoyTofu tofu = sfs.compileToTofu(); // Render the template with no data. System.out.println(tofu.newRenderer("examples.simple.helloWorld").render()); } }This example bundles the template files that you specify (in this case, just
simple.soy) into aSoyFileSetobject, then compiles the bundle into aSoyTofuobject form with a call tocompileToTofu(). The final line of code calls the template, using the template's fully qualified nameexamples.simple.helloWorld, and renders its output to standard out.To try out this example, you'll need to have Java Development Kit (JDK) version 6 installed, with the executables
javaandjavacon your path. Compile theHelloWorldclass:~/helloworld_java$ javac -classpath soy-latest.jar HelloWorld.java
Run this command to see the rendered template:
~/helloworld_java$ java -classpath .:soy-latest.jar HelloWorld
In this example,
classpathcontains the current directory (forHelloWorld.class) as well assoy-latest.jarfor theHelloWorldclass's dependencies.Note: On Windows, use a semicolon instead of a colon as the path separator.
Note: On some systems, you might need to use single quotes to delimit your classpath string.
You should see this message at standard out:
Hello world!
Add the following second template, called
.helloName, tosimple.soy. Note that.helloNametakes a required parameter calledname, which is declared by@param. It also takes an optional parametergreetingWord, which is declared by@param?. These parameters are referenced in the template body using the expressions$nameand$greetingWord, respectively. This template also demonstrates that you can conditionally include content in templates via theif-elsecommands. You can put this template before or after the.helloWorldtemplate, just as long as it's after thenamespacedeclaration./** * Greets a person using "Hello" by default. * @param name The name of the person. * @param? greetingWord Optional greeting word to use instead of "Hello". */ {template .helloName} {if not $greetingWord} Hello {$name}! {else} {$greetingWord} {$name}! {/if} {/template}Add a third template to the file. This template,
helloNames, demonstrates aforeachloop with anifemptycommand. It also shows how to call other templates and insert their output using thecallcommand. Note that thedata="all"attribute in thecallcommand passes all of the caller's template data to the callee template./** * Greets a person and optionally a list of other people. * @param name The name of the person. * @param additionalNames The additional names to greet. May be an empty list. */ {template .helloNames} // Greet the person. {call .helloName data="all" /}<br> // Greet the additional people. {foreach $additionalName in $additionalNames} {call .helloName} {param name: $additionalName /} {/call} {if not isLast($additionalName)} <br> // break after every line except the last {/if} {ifempty} No additional people to greet. {/foreach} {/template}Note: Make sure that you've added the new templates after the namespace declaration.
Now edit
HelloWorld.javaand add the lines of bolded code below (note the new import), which call the new templates and exercise them with data:import com.google.template.soy.SoyFileSet; import com.google.template.soy.data.SoyListData; import com.google.template.soy.data.SoyMapData; import com.google.template.soy.tofu.SoyTofu; import java.io.File; public class HelloWorld { public static void main (String[] args) { // Bundle the Soy files for your project into a SoyFileSet. SoyFileSet sfs = (new SoyFileSet.Builder()).add(new File("simple.soy")).build(); // Compile the template into a SoyTofu object. // SoyTofu's newRenderer method returns an object that can render any template in file set. SoyTofu tofu = sfs.compileToTofu(); // Render the template with no data. System.out.println(tofu.newRenderer("examples.simple.helloWorld").render()); // For convenience, create another SoyTofu object that has a namespace specified, // so you can pass partial template names to the newRenderer() method. SoyTofu simpleTofu = tofu.forNamespace("examples.simple"); // Hello Name example System.out.println("-----------------"); // Map the parameter "name" to the string "Ana" System.out.println(simpleTofu.newRenderer(".helloName") .setData(new SoyMapData("name", "Ana")).render()); // Hello Names example System.out.println("-----------------"); System.out.println(simpleTofu.newRenderer(".helloNames") .setData(new SoyMapData( "name", "Ana", "additionalNames", new SoyListData("Bob", "Cid", "Dee"))) .render()); } }This example exercises the
.helloNametemplate with aSoyMapDataobject in which the parameter"name"is mapped to the string"Ana". For the.helloNamestemplate, the example maps the parameter"additionalNames"to a list of strings"Bob", "Cid", "Dee".Now that you've added in new templates and updated the example to call them, re-compile and run them. You should see these messages at standard out:
~/helloworld_java$ javac -classpath soy-latest.jar HelloWorld.java ~/helloworld_java$ java -classpath .:soy-latest.jar HelloWorld Hello world! ----------------- Hello Ana! ----------------- Hello Ana!<br>Hello Bob!<br>Hello Cid!<br>Hello Dee!
That's it! Now that you've created a simple Hello World template and used it in Java, you can try more exercises in the next section.
Hello Name and Hello Names
Using Guice
If your application uses Guice, you can inject Soy classes such as SoyFileSet.Builder instead of constructing them yourself. Your Guice injector must contain SoyModule, and if your application needs localization, you should also include the appropriate message plugin module such as XliffMsgPluginModule.
For example, if you used Guice, the Hello World example from the previous section would start like this (with three additional import lines not shown):
// Create a Guice injector that contains the SoyModule and use it get a SoyFileSet.Builder.
Injector injector = Guice.createInjector(new SoyModule());
SoyFileSet.Builder sfsBuilder = injector.getInstance(SoyFileSet.Builder.class);
// Bundle the Soy files for your project into a SoyFileSet.
SoyFileSet sfs = sfsBuilder.add(new File("simple.soy")).build();
Using SoyParseInfoGenerator
You might find it error-prone to type hard-coded strings for template names and template parameters. If so, you can use SoyParseInfoGenerator to generate Java constants for the template and parameter names in your templates. Follow the steps below to use SoyParseInfoGenerator with the Hello World example:
Recall that you downloaded
SoyParseInfoGenerator.jarin an earlier step and placed the file in~/helloworld_java/. This file is a standalone executable jar that parses Soy files and generates Java classes that contain information such as template and parameter names.Run
SoyParseInfoGeneratorwith the following command-line flags:~/helloworld_java$ java -jar SoyParseInfoGenerator.jar --outputDirectory generated --javaPackage generated --javaClassNameSource filename --srcs simple.soy
This step creates the directory
~/helloworld/generatedand generates a file in it calledSimpleSoyInfo.java. This file contains mappings between the generated constants and their corresponding strings.Open
SimpleSoyInfo.javaand take a look at the constants thatSoyParseInfoGeneratorgenerated for each of the templates and their parameters. For example, the Java constantHELLO_NAMEmaps to aSoyTemplateInfoobject that represents the.helloNametemplate, and the constantHELLO_NAME.NAMEmaps to the.helloNametemplate's parameter"name".Edit
HelloWorld.javaand replace the contents of the file with the code below. Note that the differences between this file and the original are bolded.import static generated.SimpleSoyInfo.HELLO_NAME; import static generated.SimpleSoyInfo.HELLO_NAMES; import static generated.SimpleSoyInfo.HELLO_WORLD; import com.google.template.soy.SoyFileSet; import com.google.template.soy.data.SoyMapData; import com.google.template.soy.tofu.SoyTofu; import com.google.template.soy.data.SoyListData; import java.io.File; public class HelloWorld { public static void main (String[] args) { SoyFileSet sfs = (new SoyFileSet.Builder()).add(new File("simple.soy")).build(); SoyTofu tofu = sfs.compileToTofu(); System.out.println(tofu.newRenderer(HELLO_WORLD).render()); System.out.println("-----------------"); System.out.println(tofu.newRenderer(HELLO_NAME) .setData(new SoyMapData(HELLO_NAME.NAME, "Ana")).render()); System.out.println("-----------------"); System.out.println(tofu.newRenderer(HELLO_NAMES) .setData(new SoyMapData( HELLO_NAMES.NAME, "Ana", HELLO_NAMES.ADDITIONAL_NAMES, new SoyListData("Bob", "Cid", "Dee"))) .render()); } }Compile the
HelloWorldandSimpleSoyInfoclasses:~/helloworld_java$ javac -classpath soy-latest.jar HelloWorld.java generated/SimpleSoyInfo.java
Finally, re-run the example and you should see the same output as before:
~/helloworld_java$ java -classpath .:soy-latest.jar HelloWorld Hello world! ----------------- Hello Ana! ----------------- Hello Ana!<br>Hello Bob!<br>Hello Cid!<br>Hello Dee!
- To use the same templates from this chapter in JavaScript, try the Hello World Using JavaScript examples.
- To read more about Closure Templates concepts, take a look at the Concepts chapter.
You've just completed the Hello World of Closure Templates using Java. Where should you go next?