ee.mare.indrek.jtlt.TemplateException: Unknown macro [BOO] at line 54 at ee.mare.indrek.jtlt.TemplateContext.complain(TemplateContext.java:119) at ee.mare.indrek.jtlt.TemplateGenerator.parse(TemplateGenerator.java:236) at ee.mare.indrek.jtlt.TemplateGenerator.init(TemplateGenerator.java:98) at ee.mare.indrek.jtlt.TemplateGenerator.init_from_reader(TemplateGenerator.java:80) at ee.mare.indrek.jtlt.TemplateGenerator.(TemplateGenerator.java:60) at Example1.main(Example1.java:36) This is a template! To get values replaced into text we use KEY-s and replace methods. You can use the same key in multiple places inside template. Hello, world! Hello, world! You don't have to replace all keys, if they are not set they are just replaced with nothing, like here: ''! This is a sub block! It can be instanced using the lock method. Notice that keys like hw are not inherited here: ''. Had you instead used the nreplace() - nested replace - it would be here. But one that we replace inside lock is - this should be in block. Notice that the val from previous block will not be placed here: ''. That's because keys replaced inside nested blocks can't affect previous blocks. This is nested key, notice that due to 'nreplace' you should see here: nested key replacement. This is nested key, notice that due to 'nreplace' you should see here: nested key replacement. This is nested key, notice that due to 'nreplace' you should see here: nested key replacement. One more important technique is to get a mixed set of different type of rows. Just placing blocks in sequence won't work, you'd just get AAAABBBB. If we want to get ABABAB do this: This is a row of type A This is a row of type B This is a row of type A This is a row of type B Now lets test our custom macro. We registered it with name GIRLS, so we should use it like this: Little girls like to eat icecream Little girls like to drink cola Using a nonexistent macro will also just provide you with emptiness - '' but it will also file a complaint. That helps when you make typos. You should see a stacktrace at the start of the output. When you don't want to specify an argument you can omit the colon: Little girls like to sing and dance. Also whenever you use space as the first symbol - given macro is discarded as comment: '' without filing any complaints. So never register macro names that start with space. One more important feature of keys - when you replace the same key twice the second value will override the previous: set value second time This can be useful for example when you're doing bulk replace from some Map or ResultSet and later want to finetune some values. Note you can't override the key set inside a sub block from parent block.