How to customize the freemarker expression? - java

How to customize the freemarker expression, the syntax like the following
<#if name?myExpr>

You can't do that with ?. The point of the ? operator is exactly that the function names come after it are reserved for the FreeMarker Template Language, so new functions can be added to new FreeMarker releases without breaking backward-compatibility.
You can, however, add functions that are called as foo(param). I understand that people would prefer the postfix-call style (param?foo), but that has the compatibility issue mentioned. (I have also recommended param?#foo for this, but AFAIR the idea wasn't popular on the list.)

Related

Get List of all dependency names(even multi-level inheritance) from the template string in FreeMarker

I was trying to use the FreeMarker template engine in a personal maven project.
I wished to ask if FreeMarker has a public method, which, given the template body as a string can return the list of all the dependency template names (that use #import and #include directives).
If so, can you please point me to the right part of the codebase related to this?
Even if there's no such public method, can you please point me to the private method that accomplishes this?
I'm not sure if there is a way to change name of a directive in any way in FreeMarker(like aliases in bash? Or the "using" declarations in C++, or perhaps any user defined directive in FreeMarker).
If there is, writing such a simple parser could have bugs because if it does not find <#import> or <#include> directives, we will get no dependency template names, as the alias or user-defined directive.
So are there any such things that I need to pay specific attention to? Or can I write a simple parser of my own using String.indexOf() and String.substring() methods?
Thanks!
FreeMarker does pretty much everything on runtime (except basic parsing), including the resolution of #include-s and #imports. So you can have things like <#include someVariable>, <#if condition><#include "this.ftl"></#if>, etc. Therefore it's generally not possible to tell what dependencies a template have, and so there's no private API for that either. There's a non-published API to walk the AST (starting out from Template.getRootTreeNode()), and then you can try to guess, hoping that your templates aren't tricky in this regard. (Yes, it's #deprecated, but never mind, at this point it very certainly won't be ever removed from 2.x.)
Regarding aliases. Macros, functions, metods are all just values for the template language. So you can do <#assign mm = myImport.MyMacro>, and then just use mm as you would use myImport.MyMacro.

Creating your own keywords in java?

I was wondering if this would work. In java, you use 'null' to make something nothing. Would this work?
Object nil = null;
Could I then use nil instead of null? Thanks!
Java doesn't allow for this.
However, if you want to achieve this sort of syntax whilst being able to run your code on a JVM (and with other Java code), you could look at Groovy, which has operator overloading (and with which you could also use DSLs for short syntax which would have similar effects to using custom operators).
Note that defining custom operators (not just overloading) is a big deal in any language, since you would have to be able to alter the lexer and grammar somehow.

placeholder for any code

I need to define a object at runtime like below.
Filter rowFilter = new RowFilter(CompareFilter.CompareOp.EQUAL,
new RegexStringComparator(".*-.5"));
I am reading one String which is having code like below
String _filterString = "RowFilter(CompareFilter.CompareOp.EQUAL,
new RegexStringComparator(\".*-.5\"))";
Now I need to define a filter object by using the above String.
I know, this type of problems we can achieve by using Reflections.But I am looking for alternatives. Is there any simple way to solve problems like this?
The Java Scripting API allows embedding of miscellaneous languages like JavaScript and have bindings to Java variables and methods. In your case the language BeanShell (Java subset) can be used.
Java Compiler can be used for compiling at Runtime, but it requires a full source (Compilation Unit). I don't think a single expression can be compiled. Maybe, you can work out from here to get your objects from the classes compiled at runtime.

Performing complicated XPath queries in Scala

What's the simplest API to use in scala to perform the following XPath queries on a document?
//s:Annotation[#type='attitude']/s:Content/s:Parameter[#role='type' and not(text())]
//s:Annotation[s:Content/s:Parameter[#role='id' and not(text())]]/#type
(s is defined as a nickname for a particular namespace)
The only documentation I can find on Scala's XML libraries has no information on performing complicated real XPath queries.
I used to like JDOM for this purpose (in Java), but since JDOM doesn't support generics, it will be painful to work with in Scala. (Other XML libraries for Java have tended to be even more painful in Java, but I admit I don't know the landscape real well.)
//s:Annotation[#type='attitude']/s:Content/s:Parameter[#role='type' and not(text())]
Well, I don't understand the s: notation, and couldn't find it on XPath spec either. However, ignoring that this would look like this:
(
(xml
\\ "Annotation"
filter (_ \ "#type" contains Text("x"))
)
\ "Content"
\ "Parameter"
filter (el => (el \ "#type" contains Text("type")) && el.isInstanceOf[Text])
)
Note the necessity of parenthesis because of higher precedence of \ over filter. I have changed the formatting to a multi-line expression as the Scala equivalent is just way too verbose for a single line.
I can't answer about namespaces, though. No clue how to work with them on searches, if it's even possible. The docs mention #{uri}attribute for prefixed attributes, not does not mention anything about prefixed elements. Also, note that you need to pass an uri which resolves to the namespace you want, as literal namespaces in search are not supported.
I think I'm going to go with lightly pimping XOM. It's a bit of a shame the XOM authors decided against exposing collections of child nodes and the like, but they had more work and less advantage to doing so in Java than in Scala. (And it is an otherwise well-designed library.)
EDIT: I wound up pimping JDOM after all, because XOM doesn't compile XPath queries ahead of time. Since most of my effort was directed towards XPath this time, I was able to come up with a good model that sidesteps most of the generics issues. It shouldn't be too hard to come up with reasonable genericized versions of the methods getChildren and getAttributes and getAdditionalNamespaces in org.jdom.Element (by pimping the library with new methods that have slightly changed names.) I don't think there's a fix for getContent, and I'm not sure about getDescendants.
Scales Xml adds both string based full XPath evaluation and an internal DSL providing a fairly complete coverage for querying
I guess when scalaxmljaxen is mature, we'll be able to do this reliably on scala's built-in XML classes.
I would suggest using kantan.xpath:
import kantan.xpath._
import kantan.xpath.implicits._
input.evalXPath[List[String]](xp"/annotation[#type='attitude']/content/parameter[#role='type' and not(text())]/#value")
This yields:
res1: kantan.xpath.XPathResult[List[String]] = Success(List(foobar))

Implement a Custom Escaper in Freemarker

Freemarker has the ability to do text escaping using something like this:
<#escape x as x?html>
Foo: ${someVal}
Bar: ${someOtherVal}
</#escape>
xml, xhtml, and html are all built in escapers. Is there a way to register a custom written escaper? I want to generate CSV and have each individual element escaped and that seems like a good mechanism.
I'm trying to do this in Struts 2 if that matters as well.
You seem to be confusing two concepts here. ?xml, ?xhtml and ?html are string built-ins.
<#escape> OTOH is syntax sugar to save you from typing the same expression over and over again. It can be used with any expression, it's not limited to built-ins.
That said, there's unfortunately no built-in for csv string escaping and there's no way to write your own without modifying FreeMarker source (though if you do want to go this way it's pretty straightforward - take a look at freemarker.core.BuiltIn). Perhaps you can by with ?replace using regex or just write / expose an appropriate method and invoke it in your template.
The Javadoc for HtmlEscaper indicates how to instantiate/register that in code (see the header), so I suspect if you implement your own TemplateTransformModel, and register it in a similar fashion then that should work.

Categories