I'm setting up views in a Dropwizard app and ran into a curious issue with Freemarker.
Following the docs here I set up a very simple example as follows
public class ExampleFreemarkerView extends View {
private Foo foo;
public ContractHtmlView(Foo Foo) {
super("FooView.ftl");
this.foo = foo;
}
public Contract getFoo() { return foo };
}
public class Foo {
public String bar = "Hello World";
}
With FooView.ftl
<html>
<body>
<h1>${foo.bar}</h1>
</body>
</html>
Expected output when rendering ExampleFreemarkerView
is an HTML document displaying Hello World
.
What actually happens is Freemarker throws an exception, complaining that ${foo.bar}
- specifically bar
- is undefined.
This appears to be because bar
is a public field, without a getter. When I add a public String getBar() { return bar; }
getter to Foo
, it works.
I'm somewhat surprised that this is the case - i.e. that Freemarker seems to require getters and won't work with public fields out of the box. I'm deliberately using public fields instead of getters/setters on my model objects, so adding getters just to make Freemarker work isn't a solution I'll consider.
I've googled around a lot and read through the Freemarker docs, and just can't find any way to 'turn on' this behaviour in Freemarker. Is it possible?
Just for interest - I also tried the above example, exactly the same, but with a Mustache template and public fields work fine there (i.e. {{foo.bar}}
renders Hello World
without issue). That solves the immediate problem, so this question is mostly just out of curiosity or in case I decide to use Freemarker over Mustache for other reasons.
Edit based on comments - I understand that Freemarker does this (insists on getters out the box) to follow the Java Beans spec, but most libraries in the Java ecosystem support public fields - Hibernate and Jackson being prominent examples - to the extent I personally view it as an equally valid standard and find libraries not supporting it out the box surprising.