static-mustache icon indicating copy to clipboard operation
static-mustache copied to clipboard

Support for rendering non primitive types.

Open ylepikhov opened this issue 9 years ago • 9 comments

According to readme: "Any boxed or unboxed primitive type is rendered with toString method. Strings are rendered as is. Rendering of other Java-types as mustache-variable is compile-time error.".

It makes difficult to render java.util.Date or java.util.UUID or java.net.URI values.

Maybe it would be better to have an option to specify classes, which values should be rendered using overloaded Object.toString() method.

Or it would be helpful to have a sort of guide for dealing with such cases.

ylepikhov avatar Jan 13 '15 19:01 ylepikhov

Good point. Some kind of white-list should be good. We need to design the way to specify such list and share it between set of templates...

Besides, you should probably never render java.util.Date ...

sviperll avatar Jan 13 '15 21:01 sviperll

java.util.Date is just a bad example.

ylepikhov avatar Jan 14 '15 04:01 ylepikhov

Any suggestions about a way to specify toString-white-list?

sviperll avatar Jan 14 '15 09:01 sviperll

How about this:

@GenerateRenderableAdapter(
// points to src/main/resources/user.mustache file template = "user.mustache",
// adapterName can be omitted. "Renderable{{className}}Adapter" name is used by default adapterName = "RenderableHtmlUserAdapter"
_// renderable classes white list. render = {URI.class, UUID.class}_ )

ylepikhov avatar Jan 14 '15 09:01 ylepikhov

Yes, but this doesn't address sharing problem. We probably want to define per project list of classes, probably per java package list of classes...

sviperll avatar Jan 14 '15 10:01 sviperll

Ok, we can use package level annotation to define list of classes to render on package level:

@RenderableClassList({ URI.class, UUID.class }) _package my.app;_

and we can define additional classes on class level:

@GenerateRenderableAdapter(
// points to src/main/resources/user.mustache file template = "user.mustache",
// adapterName can be omitted. "Renderable{{className}}Adapter" name is used by default adapterName = "RenderableHtmlUserAdapter"
_// renderable classes white list. render = @RenderableClassList({Currency.class})_ )

or even override it:

@GenerateRenderableAdapter(
// points to src/main/resources/user.mustache file template = "user.mustache",
// adapterName can be omitted. "Renderable{{className}}Adapter" name is used by default adapterName = "RenderableHtmlUserAdapter"
_// renderable classes white list. render = @RenderableClassList(value={Currency.class}, ignoreAncestorList=true)_ )

ylepikhov avatar Jan 14 '15 11:01 ylepikhov

I'm considering something like this:

User.java:

@GenerateRenderableAdapter(

// points to src/main/resources/user.mustache file
template = "user.mustache",

// adapterName can be omitted. "Renderable{{className}}Adapter" name is used by default
adapterName = "RenderableHtmlUserAdapter"

// renderable classes white list. Default list will be defined in static-mustache
usableToStringClassList = MyList.class
)
class User {
   ...
}

MyList.java:

@ClassList({URL.class, UUID.class})
class MyList {
}

ClassList annotation can be reused in many other contexts later.

sviperll avatar Jan 16 '15 11:01 sviperll

Another concern is that we need a good default list of classes. Ideally it must be complete for JDK, and this seems not so trivial work... We shouldn't unexpectedly add new classes to default list

We can sometime add some classes, but ideally it should happen only when we switch JDK version and new JDK version introduces some new classes, like java.nio.file.Path introduced in Java 7.

sviperll avatar Jan 19 '15 11:01 sviperll

@sviperll @ylepikhov

I know this issue is an ancient issue but I think a better solution is to make static-mustache => static-handlebars. Handlebars is an extension of mustache that has helper functions (and a few other things).

Thus the above rendering of nontrivial data types could be solved with handlebar helper functions. This would be especially useful for cases like dates and internationalization.

However this is a massive undertaking as essentially you need to replace the parser with a handelbars parser. However there is a handlebars java (handlebars.java) parser so you could leverage that to build the AST instead of the current parser.

Maybe someday I'll fork this project when I have time to see how much is required to get the handlebars.java parser to work with what is already present.

agentgt avatar Jun 05 '19 16:06 agentgt