Templates API

158 views
Skip to first unread message

Dhanji R. Prasanna

unread,
Mar 25, 2011, 12:33:43 AM3/25/11
to google-s...@googlegroups.com
Hi All,

Been meaning to do this for awhile, but I have now liberated templates from the resource pages. You can use the templates API to directly render any template:

@Inject
Templates templates;

String rendered = templates.render(TClass.class, instance);

The TClass is ANY class in the path that has an @Show annotation pointing to a template file. It's not necessary that this be a real registered page class. The instance is the context you want the template to use for filling in its expressions, typically it's an instance of the backing class for that template, but again you're free to use any object or a Map of key/value pairs too.

This API also supports any Sitebricks template type: HTML, XML, MVEL, Freemarker and flat UTF-8 files with mvel expressions in them, based on extension.

There is a shortcut for using this API with the Reply artifact so you can render templates directly from your service methods:

@Get
Reply<?> getPersons() {
  return Reply.with(persons).template(Persons.class);
}

The argument passed to with() will be used as the backing context for the template.

Enjoy!

Dhanji.

Miroslav Genov

unread,
Mar 25, 2011, 2:13:17 AM3/25/11
to google-s...@googlegroups.com
Awesome feature ! Thanks Dhanji, you are doing a great job. 

Now I don't have to use any custom made template evaluator when I have to sent html content to our GWT client that is using GWT-RPC. 

BTW, Does it executes methods that are annotated with @Get or @Post ? 
--
The human knowledge belongs to the world.

John Patterson

unread,
Mar 25, 2011, 4:55:16 AM3/25/11
to google-s...@googlegroups.com
Nice work!

Is the only reason for passing TClass to read the name of the template from @Show?  If so then perhaps passing a String template name would be better?  Is the context instance ever going to not be of type TClass?  If not then the interface could become:
Templates.render(Object instance); // reads @Show from class
Templates.render(Object instance, String template); // arbitrary bean

Colin Decker

unread,
Mar 25, 2011, 10:41:37 AM3/25/11
to google-s...@googlegroups.com, Dhanji R. Prasanna
Awesome! I didn't have much chance to try it out last night, and when I did it didn't seem to work with an @Decorated page (got an exception if I added @Service). Also, does the template class have to have @Show, or can it just be a class that uses a template with the same name?

-- 
Colin

Bogdan Sulima

unread,
Mar 25, 2011, 10:57:56 AM3/25/11
to google-s...@googlegroups.com
Hi All,

really cool feature. What about documenting all these dispatching options? 
I am pretty lost in them all :) 

Best regards

Bogdan.

Dhanji R. Prasanna

unread,
Mar 25, 2011, 4:55:01 PM3/25/11
to google-s...@googlegroups.com, Bogdan Sulima
Thanks for the kind words everyone! Clarifications below.

On Sat, Mar 26, 2011 at 1:57 AM, Bogdan Sulima <bogdan...@gmail.com> wrote:
Hi All,

really cool feature. What about documenting all these dispatching options? 
I am pretty lost in them all :) 

Yep, I realize we've been awful at this! The 1.0 release will ship with a solid docsite.


On Fri, Mar 25, 2011 at 3:41 PM, Colin Decker <cgde...@gmail.com> wrote:
Awesome! I didn't have much chance to try it out last night, and when I did it didn't seem to work with an @Decorated page (got an exception if I added @Service). Also, does the template class have to have @Show, or can it just be a class that uses a template with the same name?

It currently has to have an @Show--we can make it infer the name if that's something you would find useful. It's probably a bug that it doesn't work with @Decorated pages, will look into it.
 

Miroslav Genov

 to google-sitebri.
show details 5:13 PM (14 hours ago)
Awesome feature ! Thanks Dhanji, you are doing a great job. 
Now I don't have to use any custom made template evaluator when I have to sent html content to our GWT client that is using GWT-RPC. 
BTW, Does it executes methods that are annotated with @Get or @Post ? 


By this do you mean does it execute @Get/@Post on the template class as a sort of lifecycle thing? No it currently does not... Would that be useful? The intention is to call these templates from a @Get or @Post method of a @Service anyway...

John Patterson

 to google-sitebri.
show details 7:55 PM (11 hours ago)
Nice work!

Thanks! 
 

Is the only reason for passing TClass to read the name of the template from @Show?  If so then perhaps passing a String template name would be better?

Yea, I have a use case where I tunnel multiple RPCs over a single HTTP request/resp. These are dispatched by a custom handler to my own XXXRpc classes, which the @Show works nicely for. I'm open to using arbitrary string names too, but that would make it harder to pre-process and pre-load all the templates at start time in production mode.
 
  Is the context instance ever going to not be of type TClass?  If not then the interface could become:
Templates.render(Object instance); // reads @Show from class
Templates.render(Object instance, String template); // arbitrary bean

It could be, MVEL accepts Maps as equivalent to objects for instance, so I don't want to add that restriction. We could make a convenience overload that doesn't require the Class, but then you have to deal with anonymous subclasses, proxies and such--by walking up the class hierarchy.

Dhanji.

Miroslav Genov

unread,
Mar 25, 2011, 5:23:41 PM3/25/11
to google-s...@googlegroups.com
By this do you mean does it execute @Get/@Post on the template class as a sort of lifecycle thing? No it currently does not... Would that be useful? The intention is to call these templates from a @Get or @Post method of a @Service anyway...
Yeah, My idea was for some kind of lifecycle. Now after a little re-thinking I think that you are right about this. It's only for applying of an existing template, so you can do the loading and composing stuff in the page or in the service class. 

John Patterson

unread,
Mar 25, 2011, 11:07:10 PM3/25/11
to google-s...@googlegroups.com
On 26/03/2011 03:55, Dhanji R. Prasanna wrote:
> Thanks for the kind words everyone! Clarifications below.
>
> It currently has to have an @Show--we can make it infer the name if
> that's something you would find useful. It's probably a bug that it
> doesn't work with @Decorated pages, will look into it.

The ScanAndCompileBootstrapper registers classes marked @Decorated as
embbeded pages. Perhaps this step is missing causing the decorated
pages not to be found by DecorateWidget

Dhanji R. Prasanna

unread,
Mar 26, 2011, 12:23:24 AM3/26/11
to google-s...@googlegroups.com, John Patterson
Ah yep, I think I forgot to add it in the Class scan filter--that should be a one-line fix.

Also, John could you have a look at StandardCompilers to see if I've done anything strange to prevent it from considering @Decorated pages?

Thanks!

Colin Decker

unread,
Mar 26, 2011, 6:43:52 PM3/26/11
to google-s...@googlegroups.com, John Patterson
I think perhaps what I'm wanting to do with this is a little bit different than what's possible currently. I have a page class called UserPage that's @At("/:username") @Decorated and uses a file in the same package called UserPage.html as its template (with another decorator template too of course). I'd like to continue to be able to use it as a page more than as a service, but I would like to be able to return a 404 error and a page rendered through another template when the user is not found in the get method.

Currently, an explicit check prevents me from using a @Decorated page with @Service:

java.lang.IllegalArgumentException: You cannot extend headless web services!
at com.google.common.base.Preconditions.checkArgument(Preconditions.java:88)
at com.google.sitebricks.routing.DefaultPageBook.decorate(DefaultPageBook.java:182)
at com.google.sitebricks.ScanAndCompileBootstrapper.analyseExtension(ScanAndCompileBootstrapper.java:200)
at com.google.sitebricks.ScanAndCompileBootstrapper.extendedPages(ScanAndCompileBootstrapper.java:110)
at com.google.sitebricks.ScanAndCompileBootstrapper.start(ScanAndCompileBootstrapper.java:93)

If I remove the @Decorated, combine the two templates and add @Service and @Show("UserPage.html") things work, though I have to return Reply.with(this).template(getClass()).type("text/html") from the get method.

Additionally, if I use Reply.with(new ErrorPage(message)).template(ErrorPage.class).type("text/html").notFound() and ErrorPage is @Decorated, the raw ErrorPage template is used without the decoration.

-- 
Colin

John Patterson

unread,
Mar 26, 2011, 11:56:08 PM3/26/11
to Dhanji R. Prasanna, google-s...@googlegroups.com
On 26/03/2011 11:23, Dhanji R. Prasanna wrote:
> Also, John could you have a look at StandardCompilers to see if I've
> done anything strange to prevent it from considering @Decorated pages?
>
Yeah, the problem is that @Decorated pages require registration - the
class hierarchy is analysed during scan-and-compile. This is needed for
DecorateWidget to find the decorated templates.

But with your new Templates class I could skip this step... I think.
I'll give it a crack.

Dhanji R. Prasanna

unread,
Mar 27, 2011, 7:37:17 PM3/27/11
to John Patterson, google-s...@googlegroups.com
Sweet, thanks!

John Patterson

unread,
Mar 28, 2011, 3:16:14 AM3/28/11
to Dhanji R. Prasanna, google-s...@googlegroups.com
Dhanji, I think I need templates to return a Renderable instead of a String in order to use it here.  Otherwise @Require head elements will not be rendered.  I would need to write something to separate the head content - but that is already done by Renderables.

John Patterson

unread,
Mar 28, 2011, 3:45:57 AM3/28/11
to google-s...@googlegroups.com
On 26/03/2011 03:55, Dhanji R. Prasanna wrote:
Thanks for the kind words everyone! Clarifications below.
Is the only reason for passing TClass to read the name of the template from @Show?  If so then perhaps passing a String template name would be better?

Yea, I have a use case where I tunnel multiple RPCs over a single HTTP request/resp. These are dispatched by a custom handler to my own XXXRpc classes, which the @Show works nicely for. I'm open to using arbitrary string names too, but that would make it harder to pre-process and pre-load all the templates at start time in production mode.

I can see from the implementation why it was easier to use Class than String.  But from an API point of view I found myself asking "what is the extra class needed for?".  Implementation details creeping into the API.

The @Show annotation could (should) be read by the scanner and its values passed to the template loader.  As a general architectural goal, it would be nice if all annotations were handled in a layer that used an underlying SPI (like your "JQuery for servlets") that does not use annotations at all - just configuration in plain code.  One could imagine an XML configuration option (yuck) or some other means (e.g. by naming convention) or just simply calling configuration methods directly (perfect for re-using beans not made for Sitebricks).  Also just for the sake of good structure - this separation would be nice.

I would really love to go over some of the interfaces with you as a second pair of eyes and double question "why is that there"


  Is the context instance ever going to not be of type TClass?  If not then the interface could become:
Templates.render(Object instance); // reads @Show from class
Templates.render(Object instance, String template); // arbitrary bean

It could be, MVEL accepts Maps as equivalent to objects for instance, so I don't want to add that restriction.

That would still work using the first method Templates.render(myMap) .  The page class is only used at compile time to verifiy that tempate variables match page properties.  When you pass a Map in to the compiler you do not give it any type context

My point is that passing the TClass in only serves to indirectly read @Show which indirectly specifies the template name.  I think its better to handle configuration at the higher level and be more direct at this lower service level.


We could make a convenience overload that doesn't require the Class, but then you have to deal with anonymous subclasses, proxies and such--by walking up the class hierarchy.
I think it is OK that a @Show annotation must be defined on the actual template class.  In fact @Decorated pages have made this compulsory.  Anyway, like I was writing above, I think it would be better to allow this configuration to be separated from annotation configuration.  Actually, PageBook.Page already has the page class and Renderable so it would be close to working like this now... just have to remove the need for TemplateLoader to read the @Show annotation deep down in the guts of Sitebricks.


Dhanji R. Prasanna

unread,
Mar 28, 2011, 3:47:00 AM3/28/11
to John Patterson, google-s...@googlegroups.com
Hmm, we can add an overload that does this?

Templates.renderable()

Thomas Clarisse

unread,
Nov 6, 2011, 7:12:06 AM11/6/11
to google-s...@googlegroups.com
How do I say Sitebricks that my template is a Freemaker one ?

Is it enough to have freemarker in classpath and name your template .ftl ? Because if it's enought it's not working :)

Thanks 

Patrick Lightbody

unread,
Nov 6, 2011, 10:33:06 AM11/6/11
to google-s...@googlegroups.com
For whatever reason, an ftl extension doesn't trigger it, but fml does.

--
Patrick Lightbody
Schedule a meeting with me at http://lightbody.net/schedule



Thomas Clarisse

unread,
Nov 6, 2011, 10:54:17 AM11/6/11
to google-s...@googlegroups.com
Thanks Patrick. It works !

It should be corrected because I think FTL is more use that FML.

Thomas Clarisse

unread,
Nov 6, 2011, 4:50:16 PM11/6/11
to google-s...@googlegroups.com
As you notices in another post, include directive is not working so it's not a full support of freemarker.

I'll wait for the fix you are doing on github.

Rgds

kidogo

unread,
Jul 26, 2014, 7:59:24 PM7/26/14
to google-s...@googlegroups.com, dha...@gmail.com
Works great!

Any chance this will be included into some official release?

On Thursday, May 16, 2013 4:13:21 PM UTC+3, Milan Baran wrote:
Hi,

i just made simple workaround to get Decorators working with Template API.


=mb=

Dňa piatok, 25. marca 2011 15:41:37 UTC+1 Colin Decker napísal(-a):

Dhanji R. Prasanna

unread,
Jul 26, 2014, 8:15:34 PM7/26/14
to kidogo, google-s...@googlegroups.com
Yea please submit a PR and I will merge.
Reply all
Reply to author
Forward
0 new messages