Jamon Tutorial - 10. Template Inheritance: Overriding Inherited Methods/Subtemplates
As explained in the section onTutorialSample7.html
, a subtemplate can
either be private or protected. Subtemplates defined
with the <%def subTempName>
... </%def>
tag are
private and can be accessed only within the
template that defined the subtemplate.
Subtemplates defined with the
<%method subTempName>
... </%method>
tag, however, are protected and can be accessed by templates
that inherit from the template with the subtemplate definition.
To invoke a protected subtemplate defined in a parent, a child template
simply invokes it like any other subtemplate
<& subTempName &>Usually, however, it is the parent template that invokes the subtemplate, and the parent makes the template protected so that the child can override it. For example, the template
InheritanceParentProtected.jamon
declares a title
subtemplate
for the expressed purpose of allowing the child template to
override the subtemplate in order to replace the title.
<%abstract> <%args> User2 userAccount; </%args> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title><& title; name = userAccount.getName() &></title> </head> <body> <%doc> could include a navigation bar here </%doc> <h1>Jamon</h1> <h3>a typed template engine for Java</h3> <hr> <%if userAccount.isAuthorized()%> <& *CHILD &> <%else> <em>Not authorized to view this page.</em> </%if> <%doc> could also include a footer here</%doc> </body> </html> <%method title> <%args> String name; </%args> Jamon News for <% name %> </%method>
The template that derives this template would override the title
subtemplate by using the <%override tutorialName>
... </%override>
tag.
<%override tutorialName> <%xargs> name; </%xargs> Jamon Specials for <% name %> </%override>Overridden methods take the same arguments as the method they override, although, as with template inheritance, only those arguments declared in an
<%xargs>
... </%xargs>
block will be visible within
the body of the override. Also, as with template inheritance,
only the names of the arguments are listed within the
<%xargs>
... </%xargs>
tag,
because the types of the arguments are declared in the parent template's
definition.
The template InheritanceChildProtected.jamon
, below, extends
InheritanceParentProtected.jamon
and overrides the subtemplate
title
. By overriding the title
method
InheritanceChildProtected
replaces the title that the
parent template generates.
<%extends InheritanceParentProtected> <%args> String special; </%args> <%xargs> userAccount; </%xargs> <h2>Weekly Special</h2> <% userAccount == null ? "You" : (userAccount.getName() + ", you") %>\ qualify for the special of the week! <blink><% special %></blink> <%override title> <%xargs> name; </%xargs> Jamon Specials for <% name %> </%override>
The class User2.java
takes advantage of the fact that the
InheritanceParentProtected
supports inheritance by
delegating the choice of which derived template to invoke to a
separate method and then simply calling the render()
method on the object returned. The top level controller simply has
to provide the output Writer
and the
arguments required by the parent template,
InheritanceParentProtected
, while the delegated method
selects the actual template instance and provides the arguments
required by that instance.
import java.io.OutputStreamWriter; public class User2 { private String name; private boolean authorized; public User2(String p_name, boolean p_authorized) { name = p_name; authorized = p_authorized; } public String getName() { return name; } public boolean isAuthorized() { return authorized; } public static void main(String[] args) throws Exception { User2[] users = new User2[2]; users[0] = new User2("John Public", false); users[1] = new User2("John Rockerfeller", true); for (int i=0; i<users.length; i++) { // call render() on the parent template and provide arguments processUser(args.length == 0 ? null : args[0]) .render(new OutputStreamWriter(System.out), users[i]); } } /** Chooses the correct derived template to invoke and calls * <code>makeParentRenderer()</code> on that instance. * * @param templateName the key name of the template to create * @return the <code>ParentRenderer</code> of the derived template */ private static InheritanceParentProtected.ParentRenderer processUser(String templateName) { // the default template, the special of the week if (templateName == null || "special".equalsIgnoreCase(templateName)) { return new InheritanceChildProtected() .makeParentRenderer("Jamon free this week only!"); } else { // process other derived templates here return null; } } }The result of executing this class and template is below.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>Jamon Specials for John Public </title> </head> <body> <h1>Jamon</h1> <h3>a typed template engine for Java</h3> <hr> <em>Not authorized to view this page.</em> </body> </html> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>Jamon Specials for John Rockerfeller </title> </head> <body> <h1>Jamon</h1> <h3>a typed template engine for Java</h3> <hr> <h2>Weekly Special</h2> John Rockerfeller, you qualify for the special of the week! <blink>Jamon free this week only!</blink> </body> </html>