Repository: tipsy/javalin
Pull request #1036 (2020-07-17 11:50:32)

[javalin] Expose factory method JavalinJackson.defaultObjectMapper
When a mapper is provided via JavalinJackson.configure(), we lack the ability to retain the settings of the default mapper
(namely, having the jackson-module-kotlin module registered by default, which can be surprising)

tipsy: Thanks for your PR @arnaudj. Could you elaborate on when this would be used?

Patch:
diff --git a/javalin-without-jetty/pom.xml b/javalin-without-jetty/pom.xml
index a3be46b3..b397844b 100644
--- a/javalin-without-jetty/pom.xml
+++ b/javalin-without-jetty/pom.xml
@@ -109,6 +109,7 @@
             <plugin>
                 <groupId>org.codehaus.mojo</groupId>
                 <artifactId>build-helper-maven-plugin</artifactId>
+                <version>3.2.0</version>
                 <executions>
                     <execution>
                         <phase>generate-sources</phase>
diff --git a/javalin/pom.xml b/javalin/pom.xml
index 6f429cb9..4b723b5a 100644
--- a/javalin/pom.xml
+++ b/javalin/pom.xml
@@ -81,6 +81,11 @@
             <artifactId>pebble</artifactId>
             <optional>true</optional>
         </dependency>
+        <dependency>
+            <groupId>org.jusecase</groupId>
+            <artifactId>jte</artifactId>
+            <optional>true</optional>
+        </dependency>
         <dependency>
             <groupId>com.atlassian.commonmark</groupId>
             <artifactId>commonmark</artifactId>
diff --git a/javalin/src/main/java/io/javalin/core/util/OptionalDependency.kt b/javalin/src/main/java/io/javalin/core/util/OptionalDependency.kt
index 5d9a6f09..810826fd 100644
--- a/javalin/src/main/java/io/javalin/core/util/OptionalDependency.kt
+++ b/javalin/src/main/java/io/javalin/core/util/OptionalDependency.kt
@@ -26,4 +26,5 @@ enum class OptionalDependency(val displayName: String, val testClass: String, va
     SWAGGER_CORE("Swagger Core", "io.swagger.v3.oas.models.OpenAPI", "io.swagger.core.v3", "swagger-models", "2.1.2"),
     CLASS_GRAPH("ClassGraph", "io.github.classgraph.ClassGraph", "io.github.classgraph", "classgraph", "4.8.66"),
     JVMBROTLI("Jvm-Brotli", "com.nixxcode.jvmbrotli.common.BrotliLoader", "com.nixxcode.jvmbrotli", "jvmbrotli", "0.2.0"),
+    JTE("jte", "org.jusecase.jte.TemplateEngine", "org.jusecase", "jte", "0.6.0"),
 }
diff --git a/javalin/src/main/java/io/javalin/plugin/json/JavalinJackson.kt b/javalin/src/main/java/io/javalin/plugin/json/JavalinJackson.kt
index c344af2f..def36e52 100644
--- a/javalin/src/main/java/io/javalin/plugin/json/JavalinJackson.kt
+++ b/javalin/src/main/java/io/javalin/plugin/json/JavalinJackson.kt
@@ -26,6 +26,14 @@ object JavalinJackson {
         return (objectMapper ?: defaultObjectMapper)
     }
 
+    @JvmStatic
+    fun defaultObjectMapper(): ObjectMapper = try {
+        val className = OptionalDependency.JACKSON_KT.testClass
+        ObjectMapper().registerModule(Class.forName(className).getConstructor().newInstance() as Module)
+    } catch (e: ClassNotFoundException) {
+        ObjectMapper()
+    }
+
     fun toJson(`object`: Any): String {
         Util.ensureDependencyPresent(OptionalDependency.JACKSON)
         return (objectMapper ?: defaultObjectMapper).writeValueAsString(`object`)
@@ -39,11 +47,4 @@ object JavalinJackson {
         return (objectMapper ?: defaultObjectMapper).readValue(json, clazz)
     }
 
-    private fun defaultObjectMapper(): ObjectMapper = try {
-        val className = OptionalDependency.JACKSON_KT.testClass
-        ObjectMapper().registerModule(Class.forName(className).getConstructor().newInstance() as Module)
-    } catch (e: ClassNotFoundException) {
-        ObjectMapper()
-    }
-
 }
diff --git a/javalin/src/main/java/io/javalin/plugin/rendering/JavalinRenderer.kt b/javalin/src/main/java/io/javalin/plugin/rendering/JavalinRenderer.kt
index 4d5689e4..2839ed46 100644
--- a/javalin/src/main/java/io/javalin/plugin/rendering/JavalinRenderer.kt
+++ b/javalin/src/main/java/io/javalin/plugin/rendering/JavalinRenderer.kt
@@ -9,12 +9,7 @@ package io.javalin.plugin.rendering
 import io.javalin.Javalin
 import io.javalin.http.Context
 import io.javalin.plugin.rendering.markdown.JavalinCommonmark
-import io.javalin.plugin.rendering.template.JavalinFreemarker
-import io.javalin.plugin.rendering.template.JavalinJtwig
-import io.javalin.plugin.rendering.template.JavalinMustache
-import io.javalin.plugin.rendering.template.JavalinPebble
-import io.javalin.plugin.rendering.template.JavalinThymeleaf
-import io.javalin.plugin.rendering.template.JavalinVelocity
+import io.javalin.plugin.rendering.template.*
 
 object JavalinRenderer {
 
@@ -28,6 +23,7 @@ object JavalinRenderer {
         register(JavalinPebble, ".peb", ".pebble")
         register(JavalinThymeleaf, ".html", ".tl", ".thyme", ".thymeleaf")
         register(JavalinCommonmark, ".md", ".markdown")
+        register(JavalinJte, ".jte")
     }
 
     fun renderBasedOnExtension(filePath: String, model: Map<String, Any?>, ctx: Context): String {
diff --git a/javalin/src/main/java/io/javalin/plugin/rendering/template/JavalinJte.kt b/javalin/src/main/java/io/javalin/plugin/rendering/template/JavalinJte.kt
new file mode 100644
index 00000000..de964904
--- /dev/null
+++ b/javalin/src/main/java/io/javalin/plugin/rendering/template/JavalinJte.kt
@@ -0,0 +1,38 @@
+/*
+ * Javalin - https://javalin.io
+ * Copyright 2017 David Åse
+ * Licensed under Apache 2.0: https://github.com/tipsy/javalin/blob/master/LICENSE
+ */
+
+package io.javalin.plugin.rendering.template
+
+import io.javalin.core.util.OptionalDependency
+import io.javalin.core.util.Util
+import io.javalin.http.Context
+import io.javalin.plugin.rendering.FileRenderer
+import org.jusecase.jte.TemplateEngine
+import org.jusecase.jte.output.StringOutput
+import org.jusecase.jte.resolve.DirectoryCodeResolver
+import java.io.File
+
+object JavalinJte : FileRenderer {
+
+    private var templateEngine: TemplateEngine? = null
+    private val defaultTemplateEngine: TemplateEngine by lazy { defaultJteEngine() }
+
+    @JvmStatic
+    fun configure(staticTemplateEngine: TemplateEngine) {
+        templateEngine = staticTemplateEngine
+    }
+
+    override fun render(filePath: String, model: Map<String, Any?>, ctx: Context): String {
+        Util.ensureDependencyPresent(OptionalDependency.JTE)
+
+        val stringOutput = StringOutput()
+        (templateEngine ?: defaultTemplateEngine).render(filePath, model, stringOutput)
+        return stringOutput.toString()
+    }
+
+    private fun defaultJteEngine() = TemplateEngine.create(DirectoryCodeResolver(File("src/main/jte").toPath()))
+
+}
diff --git a/pom.xml b/pom.xml
index 223bd328..a420a061 100644
--- a/pom.xml
+++ b/pom.xml
@@ -81,6 +81,7 @@
         <swagger.ui.version>3.25.2</swagger.ui.version>
         <thymeleaf.version>3.0.11.RELEASE</thymeleaf.version>
         <velocity.version>2.2</velocity.version>
+        <jte.version>0.6.0</jte.version>
 
         <!-- TEST DEPENDENCIES -->
         <assertj.version>3.15.0</assertj.version>
@@ -198,6 +199,11 @@
                 <artifactId>pebble</artifactId>
                 <version>${pebble.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.jusecase</groupId>
+                <artifactId>jte</artifactId>
+                <version>${jte.version}</version>
+            </dependency>
             <dependency>
                 <groupId>com.atlassian.commonmark</groupId>
                 <artifactId>commonmark</artifactId>


Test patch:
diff --git a/javalin/src/test/java/io/javalin/TestCustomJetty.kt b/javalin/src/test/java/io/javalin/TestCustomJetty.kt
index d152854b..347fdd02 100644
--- a/javalin/src/test/java/io/javalin/TestCustomJetty.kt
+++ b/javalin/src/test/java/io/javalin/TestCustomJetty.kt
@@ -170,25 +170,5 @@ class TestCustomJetty {
         }
     }
 
-    @Test
-    fun `no warnings in log file when adding static files to a custom server`() {
-        val baos = ByteArrayOutputStream()
-        val origErr = System.err
-        try {
-            System.setErr(PrintStream(baos))
-
-            Javalin.create {
-                it.server { Server() }
-                it.enableWebjars()
-            }
-
-            System.err.flush()
-
-            assertFalse(baos.toString().contains("WARN"))
-        } finally {
-            System.setErr(origErr)
-        }
-    }
-
 }
 
diff --git a/javalin/src/test/java/io/javalin/TestJson.kt b/javalin/src/test/java/io/javalin/TestJson.kt
index 88c8d8af..0a557724 100644
--- a/javalin/src/test/java/io/javalin/TestJson.kt
+++ b/javalin/src/test/java/io/javalin/TestJson.kt
@@ -131,4 +131,16 @@ class TestJson {
         assertThat(SerializeableObject().value2).isEqualTo(mappedBack.value2)
     }
 
+    data class SerializeableDataClass(val value1: String, val value2: String)
+
+    @Test
+    fun `can use JavalinJson with a custom object-mapper on a kotlin data class`() {
+        val jacksonKtEnabledObjectMapper = JavalinJackson.defaultObjectMapper()
+        JavalinJackson.configure(jacksonKtEnabledObjectMapper) // override mapper
+        val mapped = JavalinJson.toJson(SerializeableDataClass("First value", "Second value"))
+        val mappedBack = JavalinJson.fromJson(mapped, SerializeableDataClass::class.java)
+        assertThat("First value").isEqualTo(mappedBack.value1)
+        assertThat("Second value").isEqualTo(mappedBack.value2)
+    }
+
 }
diff --git a/javalin/src/test/java/io/javalin/TestTemplates.kt b/javalin/src/test/java/io/javalin/TestTemplates.kt
index dd73283f..201ecbdd 100644
--- a/javalin/src/test/java/io/javalin/TestTemplates.kt
+++ b/javalin/src/test/java/io/javalin/TestTemplates.kt
@@ -11,6 +11,7 @@ import com.mitchellbosecke.pebble.PebbleEngine
 import com.mitchellbosecke.pebble.loader.ClasspathLoader
 import io.javalin.plugin.rendering.FileRenderer
 import io.javalin.plugin.rendering.JavalinRenderer
+import io.javalin.plugin.rendering.template.JavalinJte
 import io.javalin.plugin.rendering.template.JavalinJtwig
 import io.javalin.plugin.rendering.template.JavalinPebble
 import io.javalin.plugin.rendering.template.JavalinVelocity
@@ -23,6 +24,9 @@ import org.jtwig.functions.FunctionRequest
 import org.jtwig.functions.SimpleJtwigFunction
 import org.jtwig.util.FunctionValueUtils
 import org.junit.Test
+import org.jusecase.jte.TemplateEngine
+import org.jusecase.jte.resolve.ResourceCodeResolver
+import java.io.File
 
 class TestTemplates {
 
@@ -137,6 +141,28 @@ class TestTemplates {
         assertThat(http.getBody("/quiz")).isEqualTo("<h1>Javalin is the best framework you will ever get</h1>")
     }
 
+    @Test
+    fun `jte works`() = TestUtil.test { app, http ->
+        try {
+            JavalinJte.configure(TemplateEngine.create(ResourceCodeResolver("templates/jte"), File("target/jte").toPath()))
+            app.get("/hello") { ctx -> ctx.render("test.jte", model("page", JteTestPage("hello", "world"))) }
+            assertThat(http.getBody("/hello")).isEqualToIgnoringNewLines("<h1>hello world!</h1>")
+        } catch (e:UnsupportedClassVersionError) {
+            // jte does require JDK 11+ to work
+        }
+    }
+
+    @Test
+    fun `jte multiple params work`() = TestUtil.test { app, http ->
+        try {
+            JavalinJte.configure(TemplateEngine.create(ResourceCodeResolver("templates/jte"), File("target/jte").toPath()))
+            app.get("/hello") { ctx -> ctx.render("multiple-params.jte", model("one", "hello", "two", "world")) }
+            assertThat(http.getBody("/hello")).isEqualToIgnoringNewLines("<h1>hello world!</h1>")
+        } catch (e:UnsupportedClassVersionError) {
+            // jte does require JDK 11+ to work
+        }
+    }
+
     @Test
     fun `markdown works`() = TestUtil.test { app, http ->
         app.get("/hello") { ctx -> ctx.render("/markdown/test.md") }
@@ -167,4 +193,6 @@ class TestTemplates {
         app.get("/hello") { ctx -> ctx.render("/templates/jtwig/multiple.dots.twig", model("message", "Hello jTwig!")) }
         assertThat(http.getBody("/hello")).isEqualTo("<h1>Hello jTwig!</h1>")
     }
+
+    data class JteTestPage(val hello:String, val world:String)
 }
diff --git a/javalin/src/test/resources/templates/jte/multiple-params.jte b/javalin/src/test/resources/templates/jte/multiple-params.jte
new file mode 100644
index 00000000..49620e8a
--- /dev/null
+++ b/javalin/src/test/resources/templates/jte/multiple-params.jte
@@ -0,0 +1,3 @@
+@param String one
+@param String two
+<h1>${one} ${two}!</h1>
diff --git a/javalin/src/test/resources/templates/jte/test.jte b/javalin/src/test/resources/templates/jte/test.jte
new file mode 100644
index 00000000..82ad6b50
--- /dev/null
+++ b/javalin/src/test/resources/templates/jte/test.jte
@@ -0,0 +1,3 @@
+@import io.javalin.TestTemplates.JteTestPage
+@param JteTestPage page
+<h1>${page.getHello()} ${page.getWorld()}!</h1>