我正在Dropwizard应用程序中设置视图,并在Freemarker上遇到了一个奇怪的问题。
按照这里的文档,我设置了一个非常简单的示例,如下所示
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";
}
与FooView.ftl
<html>
<body>
<h1>${foo.bar}</h1>
</body>
</html>
呈现时的预期输出ExampleFreemarkerView
是显示Hello World
的 HTML 文档。
实际发生的是Freemarker抛出一个异常,抱怨${foo.bar}
- 特别是bar
- 是未定义的。
这似乎是因为bar
是一个公共领域,没有getter。当我将public String getBar() { return bar; }
吸气剂添加到Foo
时,它可以工作。
我有点惊讶这种情况 - 即 Freemarker 似乎需要 getter,并且不会与开箱即用的公共字段一起使用。我故意在我的模型对象上使用公共字段而不是getter/setter,所以添加getter只是为了让Freemarker工作不是我会考虑的解决方案。
我已经用谷歌搜索了很多并通读了Freemarker文档,只是找不到任何方法可以在Freemarker中"打开"这种行为。可能吗?
只是为了感兴趣 - 我也尝试了上面的例子,完全相同,但使用 Mustache 模板和公共字段在那里工作正常(即{{foo.bar}}
呈现Hello World
没有问题)。这解决了眼前的问题,所以这个问题主要只是出于好奇,或者万一我出于其他原因决定使用 Freemark 而不是 Mustache。
根据评论进行编辑-我知道 Freemarker 这样做(坚持开箱即用)遵循 Java Beans 规范,但 Java 生态系统中的大多数库都支持公共领域 - Hibernate 和 Jackson 就是突出的例子 - 在某种程度上,我个人认为它是一个同样有效的标准,并且发现库不支持它开箱即用令人惊讶。
这一切都取决于objectWrapper
配置设置。大多数项目正在使用的DefaultObjectWrapper
(以及任何BeansWrapper
子类)具有可设置为true
的exposeFields
设置。
在 Dropwizard 中,如果您以兼容的方式(基于 https://github.com/apache/freemarker-online-tester)设置ViewBundle
,则可以在配置 YML 中像这样完成此操作:
viewRendererConfiguration:
freemarker: # was `.ftl:` before Dropwizard 1.3.0
objectWrapper=DefaultObjectWrapper(2.3.28, exposeFields=true)
它在自由标记文档中有说明
每个对象都将包装到一个 TemplateHashModel 中,该模型将公开对象的 JavaBeans 属性和方法。这样,您可以在模板中使用 model.foo 来调用 obj.getFoo() 或 obj.isFoo() 方法。(请注意,公共字段不直接可见;您必须为它们编写 getter 方法。
请注意,它也遵循Java封装概念。
您也可以仅使用类注释自动将框架用作龙目岛获取者