Skip to content

Commit 54614a2

Browse files
committed
Renderer improvements
- Add builder object for handlebars and freemarker - Add Java8 modules to Jackson + unit test
1 parent 88f1801 commit 54614a2

File tree

8 files changed

+325
-42
lines changed

8 files changed

+325
-42
lines changed

jooby/src/main/java/io/jooby/Env.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,19 @@ public Env(final String name) {
8585
return name;
8686
}
8787

88+
public boolean matches(String... names) {
89+
return Stream.of(names)
90+
.anyMatch(it -> it.equalsIgnoreCase(this.name));
91+
}
92+
93+
public boolean matches(@Nonnull String name) {
94+
return this.name.equalsIgnoreCase(name);
95+
}
96+
97+
public static Env empty(String name) {
98+
return new Env(name);
99+
}
100+
88101
@Override public String toString() {
89102
StringBuilder buff = new StringBuilder();
90103
buff.append(name).append("\n");
Lines changed: 80 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,106 @@
11
package io.jooby.freemarker;
22

3+
import freemarker.cache.CacheStorage;
34
import freemarker.cache.ClassTemplateLoader;
5+
import freemarker.cache.NullCacheStorage;
46
import freemarker.cache.TemplateLoader;
57
import freemarker.core.HTMLOutputFormat;
8+
import freemarker.core.OutputFormat;
69
import freemarker.template.Configuration;
7-
import freemarker.template.ObjectWrapper;
810
import freemarker.template.Template;
911
import freemarker.template.TemplateException;
10-
import freemarker.template.TemplateHashModel;
11-
import freemarker.template.TemplateModel;
1212
import io.jooby.Context;
13+
import io.jooby.Env;
1314
import io.jooby.ModelAndView;
1415
import io.jooby.TemplateEngine;
1516
import io.jooby.Throwing;
1617

18+
import javax.annotation.Nonnull;
1719
import java.io.StringWriter;
1820
import java.util.HashMap;
1921
import java.util.Map;
20-
import java.util.Properties;
22+
23+
import static java.util.Optional.ofNullable;
2124

2225
public class Freemarker implements TemplateEngine {
2326

24-
private final Configuration freemarker;
27+
public static class Builder {
2528

26-
public Freemarker(Configuration freemarker) {
27-
this.freemarker = freemarker;
28-
}
29+
private TemplateLoader loader;
2930

30-
public Freemarker() {
31-
this(create(new ClassTemplateLoader(Freemarker.class.getClassLoader(), "/views"), options()));
32-
}
31+
private Map<String, String> settings = new HashMap<>();
3332

34-
public static Properties options() {
35-
Properties properties = new Properties();
36-
properties.setProperty("object_wrapper", "default");
37-
properties.setProperty("template_exception_handler", "default");
38-
properties.setProperty("defaultEncoding", "UTF-8");
39-
return properties;
40-
}
33+
private CacheStorage cacheStorage;
34+
35+
private OutputFormat outputFormat = HTMLOutputFormat.INSTANCE;
36+
37+
public Builder templateLoader(@Nonnull TemplateLoader loader) {
38+
this.loader = loader;
39+
return this;
40+
}
41+
42+
public Builder setting(@Nonnull String name, @Nonnull String value) {
43+
this.settings.put(name, value);
44+
return this;
45+
}
46+
47+
public Builder cache(@Nonnull CacheStorage cacheStorage) {
48+
this.cacheStorage = cacheStorage;
49+
return this;
50+
}
51+
52+
public Builder outputFormat(@Nonnull OutputFormat outputFormat) {
53+
this.outputFormat = outputFormat;
54+
return this;
55+
}
4156

42-
public static Configuration create(TemplateLoader loader, Properties options) {
43-
try {
57+
public Freemarker build() {
58+
return build(Env.empty("dev"));
59+
}
60+
61+
public Freemarker build(@Nonnull Env env) {
4462
Configuration freemarker = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
45-
freemarker.setSettings(options);
46-
freemarker.setTemplateLoader(loader);
47-
freemarker.setOutputFormat(HTMLOutputFormat.INSTANCE);
48-
return freemarker;
49-
} catch (TemplateException x) {
50-
throw Throwing.sneakyThrow(x);
63+
freemarker.setOutputFormat(outputFormat);
64+
65+
// Settings
66+
env.get("freemarker").toMap().forEach(settings::putIfAbsent);
67+
settings.putIfAbsent("defaultEncoding", "UTF-8");
68+
settings.forEach((k, v) -> {
69+
try {
70+
freemarker.setSetting(k, v);
71+
} catch (TemplateException x) {
72+
throw Throwing.sneakyThrow(x);
73+
}
74+
});
75+
76+
freemarker.setTemplateLoader(ofNullable(loader).orElseGet(this::defaultTemplateLoader));
77+
78+
CacheStorage cache = ofNullable(cacheStorage).orElseGet(() ->
79+
env.matches("dev", "test") ? NullCacheStorage.INSTANCE : null
80+
);
81+
if (cache != null) {
82+
freemarker.setCacheStorage(cache);
83+
}
84+
85+
// clear
86+
this.loader = null;
87+
this.settings.clear();
88+
this.settings = null;
89+
this.cacheStorage = null;
90+
return new Freemarker(freemarker);
91+
}
92+
93+
private TemplateLoader defaultTemplateLoader() {
94+
return new ClassTemplateLoader(getClass().getClassLoader(), "/views");
5195
}
5296
}
5397

98+
private final Configuration freemarker;
99+
100+
public Freemarker(Configuration freemarker) {
101+
this.freemarker = freemarker;
102+
}
103+
54104
@Override public String apply(Context ctx, ModelAndView modelAndView) throws Exception {
55105
Template template = freemarker.getTemplate(modelAndView.view);
56106
StringWriter writer = new StringWriter();
@@ -59,4 +109,8 @@ public static Configuration create(TemplateLoader loader, Properties options) {
59109
template.process(model, writer);
60110
return writer.toString();
61111
}
112+
113+
public static Freemarker.Builder builder() {
114+
return new Freemarker.Builder();
115+
}
62116
}

modules/jooby-freemarker/src/test/java/io/jooby/freemarker/FreemarkerTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.jooby.freemarker;
22

3+
import io.jooby.Env;
34
import io.jooby.MockContext;
45
import io.jooby.ModelAndView;
56
import org.junit.jupiter.api.Test;
@@ -29,7 +30,7 @@ public String getLastname() {
2930

3031
@Test
3132
public void render() throws Exception {
32-
Freemarker freemarker = new Freemarker();
33+
Freemarker freemarker = Freemarker.builder().build(Env.empty("test"));
3334
String output = freemarker
3435
.apply(new MockContext().set("local", "var"), new ModelAndView("index.ftl")
3536
.put("user", new User("foo", "bar"))
Lines changed: 125 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,144 @@
11
package io.jooby.handlebars;
22

3+
import com.github.jknack.handlebars.Decorator;
34
import com.github.jknack.handlebars.Handlebars;
5+
import com.github.jknack.handlebars.Helper;
46
import com.github.jknack.handlebars.Template;
7+
import com.github.jknack.handlebars.cache.HighConcurrencyTemplateCache;
8+
import com.github.jknack.handlebars.cache.NullTemplateCache;
9+
import com.github.jknack.handlebars.cache.TemplateCache;
510
import com.github.jknack.handlebars.io.ClassPathTemplateLoader;
611
import com.github.jknack.handlebars.io.TemplateLoader;
712
import io.jooby.Context;
13+
import io.jooby.Env;
814
import io.jooby.ModelAndView;
915
import io.jooby.TemplateEngine;
1016

17+
import java.io.File;
18+
import java.io.IOException;
19+
import java.io.InputStream;
20+
import java.io.Reader;
21+
import java.net.URI;
22+
import java.nio.charset.Charset;
1123
import java.nio.charset.StandardCharsets;
1224
import java.util.HashMap;
1325
import java.util.Map;
1426

27+
import static java.util.Optional.ofNullable;
28+
1529
public class Hbs implements TemplateEngine {
1630

17-
private Handlebars handlebars;
31+
public static class Builder {
1832

19-
public Hbs(Handlebars handlebars) {
20-
this.handlebars = handlebars;
21-
}
33+
private Handlebars handlebars;
34+
35+
private TemplateLoader loader;
36+
37+
private TemplateCache cache;
38+
39+
public Builder() {
40+
handlebars = new Handlebars();
41+
handlebars.setCharset(StandardCharsets.UTF_8);
42+
}
43+
44+
public Builder cache(TemplateCache cache) {
45+
this.cache = cache;
46+
return this;
47+
}
48+
49+
public Builder loader(TemplateLoader loader) {
50+
this.loader = loader;
51+
return this;
52+
}
53+
54+
public <H> Builder registerHelper(String name, Helper<H> helper) {
55+
handlebars.registerHelper(name, helper);
56+
return this;
57+
}
58+
59+
public <H> Builder registerHelperMissing(Helper<H> helper) {
60+
handlebars.registerHelperMissing(helper);
61+
return this;
62+
}
63+
64+
public Builder registerHelpers(Object helperSource) {
65+
handlebars.registerHelpers(helperSource);
66+
return this;
67+
}
68+
69+
public Builder registerHelpers(Class<?> helperSource) {
70+
handlebars.registerHelpers(helperSource);
71+
return this;
72+
}
73+
74+
public Builder registerHelpers(URI location) throws Exception {
75+
handlebars.registerHelpers(location);
76+
return this;
77+
}
78+
79+
public Builder registerHelpers(File input) throws Exception {
80+
handlebars.registerHelpers(input);
81+
return this;
82+
}
2283

23-
public Hbs() {
24-
this(build(new ClassPathTemplateLoader("/views", "")));
84+
public Builder registerHelpers(String filename, Reader source)
85+
throws Exception {
86+
handlebars.registerHelpers(filename, source);
87+
return this;
88+
}
89+
90+
public Builder registerHelpers(String filename, InputStream source)
91+
throws Exception {
92+
handlebars.registerHelpers(filename, source);
93+
return this;
94+
}
95+
96+
public Builder registerHelpers(String filename, String source)
97+
throws IOException {
98+
handlebars.registerHelpers(filename, source);
99+
return this;
100+
}
101+
102+
public Builder registerDecorator(String name, Decorator decorator) {
103+
handlebars.registerDecorator(name, decorator);
104+
return this;
105+
}
106+
107+
public Builder charset(Charset charset) {
108+
handlebars.setCharset(charset);
109+
return this;
110+
}
111+
112+
public Hbs build() {
113+
return build(Env.empty("dev"));
114+
}
115+
116+
public Hbs build(Env env) {
117+
handlebars.with(ofNullable(loader).orElseGet(this::defaultTemplateLoader));
118+
119+
TemplateCache cache = ofNullable(this.cache).orElseGet(() ->
120+
env.matches("dev", "test") ?
121+
NullTemplateCache.INSTANCE :
122+
new HighConcurrencyTemplateCache()
123+
);
124+
handlebars.with(cache);
125+
126+
Hbs result = new Hbs(handlebars);
127+
this.loader = null;
128+
this.handlebars = null;
129+
this.cache = null;
130+
return result;
131+
}
132+
133+
private TemplateLoader defaultTemplateLoader() {
134+
return new ClassPathTemplateLoader("/views", "");
135+
}
25136
}
26137

27-
public static Handlebars build(TemplateLoader loader) {
28-
Handlebars handlebars = new Handlebars(loader);
29-
handlebars.setCharset(StandardCharsets.UTF_8);
30-
return handlebars;
138+
private Handlebars handlebars;
139+
140+
public Hbs(Handlebars handlebars) {
141+
this.handlebars = handlebars;
31142
}
32143

33144
@Override public String apply(Context ctx, ModelAndView modelAndView) throws Exception {
@@ -36,4 +147,8 @@ public static Handlebars build(TemplateLoader loader) {
36147
model.putAll(modelAndView.model);
37148
return template.apply(model);
38149
}
150+
151+
public static Hbs.Builder builder() {
152+
return new Hbs.Builder();
153+
}
39154
}

modules/jooby-handlebars/src/test/java/io/jooby/handlebars/HbsTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public String getLastname() {
2828

2929
@Test
3030
public void render() throws Exception {
31-
Hbs engine = new Hbs();
31+
Hbs engine = Hbs.builder().build();
3232
String output = engine
3333
.apply(new MockContext().set("local", "var"), new ModelAndView("index.hbs")
3434
.put("user", new User("foo", "bar"))

modules/jooby-jackson/pom.xml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,26 @@
3232
<artifactId>jackson-databind</artifactId>
3333
</dependency>
3434

35+
<dependency>
36+
<groupId>com.fasterxml.jackson.datatype</groupId>
37+
<artifactId>jackson-datatype-jdk8</artifactId>
38+
</dependency>
39+
40+
<dependency>
41+
<groupId>com.fasterxml.jackson.datatype</groupId>
42+
<artifactId>jackson-datatype-jsr310</artifactId>
43+
</dependency>
44+
45+
<dependency>
46+
<groupId>com.fasterxml.jackson.module</groupId>
47+
<artifactId>jackson-module-parameter-names</artifactId>
48+
</dependency>
49+
50+
<dependency>
51+
<groupId>com.fasterxml.jackson.module</groupId>
52+
<artifactId>jackson-module-afterburner</artifactId>
53+
</dependency>
54+
3555
<!-- Test dependencies -->
3656
<dependency>
3757
<groupId>org.junit.jupiter</groupId>
@@ -63,5 +83,13 @@
6383
<artifactId>okhttp</artifactId>
6484
<scope>test</scope>
6585
</dependency>
86+
87+
<dependency>
88+
<groupId>io.jooby</groupId>
89+
<artifactId>jooby</artifactId>
90+
<version>${jooby.version}</version>
91+
<classifier>tests</classifier>
92+
<scope>test</scope>
93+
</dependency>
6694
</dependencies>
6795
</project>

0 commit comments

Comments
 (0)