Skip to content

Commit 372430a

Browse files
committed
Template engines are broken
- Add custom exception - Remove eager filtering so fails with better error message - fix #3562
1 parent badd7ae commit 372430a

12 files changed

Lines changed: 106 additions & 21 deletions

File tree

jooby/src/main/java/io/jooby/ModelAndView.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
import java.util.Locale;
99
import java.util.Map;
10+
import java.util.Set;
11+
import java.util.stream.Collectors;
1012

1113
import edu.umd.cs.findbugs.annotations.NonNull;
1214
import edu.umd.cs.findbugs.annotations.Nullable;
@@ -19,6 +21,21 @@
1921
*/
2022
public class ModelAndView<T> {
2123

24+
/** Thrown by template engine when they are not capable of rendering a {@link ModelAndView}. */
25+
public static class UnsupportedModelAndView extends IllegalArgumentException {
26+
/**
27+
* Constructor.
28+
*
29+
* @param supported List of supported model implementation.
30+
*/
31+
public UnsupportedModelAndView(Class<?>... supported) {
32+
super(
33+
"Only "
34+
+ Set.of(supported).stream().map(Class::getName).collect(Collectors.joining(", "))
35+
+ " are supported");
36+
}
37+
}
38+
2239
/** View name. */
2340
private final String view;
2441

jooby/src/main/java/io/jooby/TemplateEngine.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public interface TemplateEngine extends MessageEncoder {
3434
* @return Rendered template.
3535
* @throws Exception If something goes wrong.
3636
*/
37-
DataBuffer render(Context ctx, ModelAndView modelAndView) throws Exception;
37+
DataBuffer render(Context ctx, ModelAndView<?> modelAndView) throws Exception;
3838

3939
@Override
4040
default DataBuffer encode(@NonNull Context ctx, @NonNull Object value) throws Exception {

modules/jooby-freemarker/src/main/java/io/jooby/freemarker/FreemarkerTemplateEngine.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public List<String> extensions() {
3333
}
3434

3535
@Override
36-
public DataBuffer render(Context ctx, ModelAndView modelAndView) throws Exception {
36+
public DataBuffer render(Context ctx, ModelAndView<?> modelAndView) throws Exception {
3737
var buffer = ctx.getBufferFactory().allocateBuffer();
3838
var template = freemarker.getTemplate(modelAndView.getView());
3939
var writer = buffer.asWriter();

modules/jooby-handlebars/src/main/java/io/jooby/internal/handlebars/HandlebarsTemplateEngine.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public List<String> extensions() {
3535
}
3636

3737
@Override
38-
public DataBuffer render(Context ctx, ModelAndView modelAndView) throws Exception {
38+
public DataBuffer render(Context ctx, ModelAndView<?> modelAndView) throws Exception {
3939
var template = handlebars.compile(modelAndView.getView());
4040
var engineModel =
4141
com.github.jknack.handlebars.Context.newBuilder(modelAndView.getModel())

modules/jooby-jte/src/main/java/io/jooby/jte/JteTemplateEngine.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public List<String> extensions() {
3232
}
3333

3434
@Override
35-
public DataBuffer render(Context ctx, ModelAndView modelAndView) {
35+
public DataBuffer render(Context ctx, ModelAndView<?> modelAndView) {
3636
var buffer = ctx.getBufferFactory().allocateBuffer();
3737
var output = new DataBufferOutput(buffer, StandardCharsets.UTF_8);
3838
var attributes = ctx.getAttributes();

modules/jooby-pebble/src/main/java/io/jooby/pebble/PebbleTemplateEngine.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,7 @@ public List<String> extensions() {
3434
}
3535

3636
@Override
37-
public boolean supports(@NonNull ModelAndView modelAndView) {
38-
return TemplateEngine.super.supports(modelAndView) && modelAndView instanceof MapModelAndView;
39-
}
40-
41-
@Override
42-
public DataBuffer render(Context ctx, ModelAndView modelAndView) throws Exception {
37+
public DataBuffer render(Context ctx, ModelAndView<?> modelAndView) throws Exception {
4338
if (modelAndView instanceof MapModelAndView mapModelAndView) {
4439
var buffer = ctx.getBufferFactory().allocateBuffer();
4540
var template = engine.getTemplate(modelAndView.getView());
@@ -52,8 +47,7 @@ public DataBuffer render(Context ctx, ModelAndView modelAndView) throws Exceptio
5247
template.evaluate(buffer.asWriter(), model, locale);
5348
return buffer;
5449
} else {
55-
throw new IllegalArgumentException(
56-
"Only " + MapModelAndView.class.getName() + " are supported");
50+
throw new ModelAndView.UnsupportedModelAndView(MapModelAndView.class);
5751
}
5852
}
5953
}

modules/jooby-pebble/src/test/java/io/jooby/pebble/PebbleModuleTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77

88
import static java.util.Collections.singletonList;
99
import static org.junit.jupiter.api.Assertions.assertEquals;
10+
import static org.junit.jupiter.api.Assertions.assertThrows;
1011

1112
import java.nio.charset.StandardCharsets;
1213
import java.nio.file.Paths;
1314
import java.util.Collections;
1415
import java.util.Locale;
16+
import java.util.Map;
1517

1618
import org.junit.jupiter.api.Test;
1719

@@ -59,6 +61,19 @@ public void render() throws Exception {
5961
assertEquals("Hello foo bar var!", output.toString(StandardCharsets.UTF_8));
6062
}
6163

64+
@Test
65+
public void shouldUnsupportedModelAndView() {
66+
PebbleEngine.Builder builder =
67+
PebbleModule.create()
68+
.build(new Environment(getClass().getClassLoader(), ConfigFactory.empty()));
69+
PebbleTemplateEngine engine =
70+
new PebbleTemplateEngine(builder, Collections.singletonList(".peb"));
71+
MockContext ctx = new MockContext();
72+
assertThrows(
73+
ModelAndView.UnsupportedModelAndView.class,
74+
() -> engine.render(ctx, new ModelAndView<>("index.peb", Map.of("foo", "bar"))));
75+
}
76+
6277
@Test
6378
public void renderFileSystem() throws Exception {
6479
PebbleEngine.Builder builder =

modules/jooby-thymeleaf/src/main/java/io/jooby/internal/thymeleaf/ThymeleafTemplateEngine.java

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,7 @@ public List<String> extensions() {
3434
}
3535

3636
@Override
37-
public boolean supports(@NonNull ModelAndView modelAndView) {
38-
return io.jooby.TemplateEngine.super.supports(modelAndView)
39-
&& modelAndView instanceof MapModelAndView;
40-
}
41-
42-
@Override
43-
public DataBuffer render(io.jooby.Context ctx, ModelAndView modelAndView) {
37+
public @NonNull DataBuffer render(io.jooby.Context ctx, ModelAndView<?> modelAndView) {
4438
if (modelAndView instanceof MapModelAndView mapModelAndView) {
4539
Map<String, Object> model = new HashMap<>(ctx.getAttributes());
4640
model.putAll(mapModelAndView.getModel());
@@ -59,8 +53,7 @@ public DataBuffer render(io.jooby.Context ctx, ModelAndView modelAndView) {
5953
templateEngine.process(templateName, context, buffer.asWriter());
6054
return buffer;
6155
} else {
62-
throw new IllegalArgumentException(
63-
"Only " + MapModelAndView.class.getName() + " are supported");
56+
throw new ModelAndView.UnsupportedModelAndView(MapModelAndView.class);
6457
}
6558
}
6659
}

tests/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@
6363
<artifactId>jooby-handlebars</artifactId>
6464
<version>${jooby.version}</version>
6565
</dependency>
66+
<dependency>
67+
<groupId>io.jooby</groupId>
68+
<artifactId>jooby-pebble</artifactId>
69+
<version>${jooby.version}</version>
70+
</dependency>
6671
<dependency>
6772
<groupId>io.jooby</groupId>
6873
<artifactId>jooby-freemarker</artifactId>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package io.jooby.i3562;
7+
8+
import static org.junit.jupiter.api.Assertions.assertEquals;
9+
10+
import java.util.Map;
11+
12+
import io.jooby.ModelAndView;
13+
import io.jooby.junit.ServerTest;
14+
import io.jooby.junit.ServerTestRunner;
15+
import io.jooby.pebble.PebbleModule;
16+
import io.jooby.thymeleaf.ThymeleafModule;
17+
18+
public class Issue3562 {
19+
@ServerTest
20+
public void unsupportedModelAndView(ServerTestRunner runner) {
21+
runner
22+
.define(
23+
app -> {
24+
app.install(new ThymeleafModule());
25+
app.install(new PebbleModule());
26+
27+
app.get(
28+
"/3562/thymeleaf",
29+
ctx -> new ModelAndView<>("index.html", Map.of("name", "thymeleaf")));
30+
app.get(
31+
"/3562/pebble",
32+
ctx -> new ModelAndView<>("index.pebble", Map.of("name", "Pebble")));
33+
34+
app.error((ctx, cause, status) -> ctx.send(cause.getMessage()));
35+
})
36+
.ready(
37+
client -> {
38+
client.get(
39+
"/3562/thymeleaf",
40+
rsp -> {
41+
assertEquals(
42+
"Only io.jooby.MapModelAndView are supported", rsp.body().string().trim());
43+
});
44+
client.get(
45+
"/3562/pebble",
46+
rsp -> {
47+
assertEquals(
48+
"Only io.jooby.MapModelAndView are supported", rsp.body().string().trim());
49+
});
50+
});
51+
}
52+
}

0 commit comments

Comments
 (0)