Repository: tipsy/javalin
Pull request #999 (2020-06-07 12:00:53)

fixed OpenAPI logging verbosity for undocumented handler
this is a follow-up to issue #997


Patch:
diff --git a/javalin-openapi/src/main/java/io/javalin/plugin/openapi/dsl/extractDocumentation.kt b/javalin-openapi/src/main/java/io/javalin/plugin/openapi/dsl/extractDocumentation.kt
index a82cb9b8..0d4895c3 100644
--- a/javalin-openapi/src/main/java/io/javalin/plugin/openapi/dsl/extractDocumentation.kt
+++ b/javalin-openapi/src/main/java/io/javalin/plugin/openapi/dsl/extractDocumentation.kt
@@ -94,7 +94,6 @@ private fun HandlerMetaInfo.getOpenApiAnnotationFromHandler(): OpenApi? {
         val method = rfl(handler).getMethodByName("handle")!!
         method.getOpenApiAnnotation()
     } catch (e: NullPointerException) {
-        localLogger.error("cannot match handler: $httpMethod path: $path --  NullPointerException", e)
         return null
     }
 }
@@ -195,7 +194,7 @@ private fun HandlerMetaInfo.findMethodByOpenApiAnnotation(methods: Array<Method>
 
 private fun HandlerMetaInfo.findFieldByOpenApiAnnotation(allFields: Array<Field>): Field? {
     if (allFields.isEmpty()) {
-        localLogger.warn("cannot match handler: $httpMethod path: $path -- no fields declared")
+        // no fields declared -> handler cannot be a field-type declaration
         return null
     }
     // filter only implementations that are derived from the Handler interface
@@ -309,21 +308,13 @@ private fun HandlerMetaInfo.findFieldByOpenApiAnnotation(allFields: Array<Field>
 }
 
 fun Method.getOpenApiAnnotation(): OpenApi? {
-    val result = getAnnotation(OpenApi::class.java)
-    if (result == null) {
-        localLogger.warn("cannot match handler -- missing OpenAPI method annotation: " + declaringLocation())
-        return null
-    }
+    val result = getAnnotation(OpenApi::class.java) ?: return null
     result.warnUserAboutPotentialBugs(this.declaringClass)
     return result
 }
 
 fun Field.getOpenApiAnnotation(): OpenApi? {
-    val result = getAnnotation(OpenApi::class.java)
-    if (result == null) {
-        localLogger.warn("cannot match handler -- missing OpenAPI field annotation: " + declaringLocation())
-        return null
-    }
+    val result = getAnnotation(OpenApi::class.java) ?: return null
     result.warnUserAboutPotentialBugs(this.declaringClass)
     return result
 }
diff --git a/javalin/src/main/java/io/javalin/http/util/ContextUtil.kt b/javalin/src/main/java/io/javalin/http/util/ContextUtil.kt
index 8cb12f54..447c1674 100644
--- a/javalin/src/main/java/io/javalin/http/util/ContextUtil.kt
+++ b/javalin/src/main/java/io/javalin/http/util/ContextUtil.kt
@@ -34,7 +34,7 @@ object ContextUtil {
 
     fun splitKeyValueStringAndGroupByKey(string: String, charset: String): Map<String, List<String>> {
         return if (string.isEmpty()) mapOf() else string.split("&").map { it.split("=", limit = 2) }.groupBy(
-                { it[0] },
+                { URLDecoder.decode(it[0], charset) },
                 { if (it.size > 1) URLDecoder.decode(it[1], charset) else "" }
         ).mapValues { it.value.toList() }
     }


Test patch:
diff --git a/javalin/src/test/java/io/javalin/TestBodyReading.kt b/javalin/src/test/java/io/javalin/TestBodyReading.kt
index 29fb84e3..367483ab 100644
--- a/javalin/src/test/java/io/javalin/TestBodyReading.kt
+++ b/javalin/src/test/java/io/javalin/TestBodyReading.kt
@@ -11,6 +11,8 @@ import io.javalin.testing.TestUtil
 import org.assertj.core.api.Assertions.assertThat
 import org.junit.Test
 import java.io.ByteArrayInputStream
+import java.net.URLEncoder
+import java.nio.charset.StandardCharsets
 
 class TestBodyReading {
 
@@ -75,9 +77,17 @@ class TestBodyReading {
                 ctx.result(formParamString)
             }
         }
-        val params = "a=1&a=2&a=3&b=1&b=2&c=1&d=&e&f=%28%23%29"
+        val params = "a=1" +      // single value
+                "&b=1&b=2&b=3" +  // multiple values
+                "&c=1=1" +        // value with '=' character
+                "&d=" +           // empty value
+                "&e" +            // also empty value
+                "&f=" + urlEncode("( # )") +   // %-encoded value with special chars
+                "&" + urlEncode("<g>") + "=g"  // %-encoded key with special chars
         val response = http.post("/body-reader?$params").body(params).asString()
-        assertThat(response.body).isEqualTo("a: 1, as: [1, 2, 3]. b: 1, bs: [1, 2]. c: 1, cs: [1]. d: , ds: []. e: , es: []. f: (#), fs: [(#)]")
+        assertThat(response.body).isEqualTo("a: 1, as: [1]. b: 1, bs: [1, 2, 3]. c: 1=1, cs: [1=1]. d: , ds: []. e: , es: []. f: ( # ), fs: [( # )]. <g>: g, <g>s: [g]")
     }
 
+    private fun urlEncode(text: String) = URLEncoder.encode(text, StandardCharsets.UTF_8.name())
+
 }