diff --git a/jooby/src/main/java/io/jooby/Context.java b/jooby/src/main/java/io/jooby/Context.java
index 1f5be9f676..5017687243 100644
--- a/jooby/src/main/java/io/jooby/Context.java
+++ b/jooby/src/main/java/io/jooby/Context.java
@@ -817,6 +817,19 @@ default Locale locale() {
*/
Value form(@NonNull String name);
+ /**
+ * Get a form field that matches the given name.
+ *
+ *
File upload retrieval is available using {@link Context#file(String)}.
+ *
+ *
Only for multipart/form-data request.
+ *
+ * @param name Field name.
+ * @param defaultValue Default value.
+ * @return Multipart value.
+ */
+ Value form(@NonNull String name, @NonNull String defaultValue);
+
/**
* Convert form data to the given type.
*
diff --git a/jooby/src/main/java/io/jooby/DefaultContext.java b/jooby/src/main/java/io/jooby/DefaultContext.java
index 40edf0cb25..eec97ffd45 100644
--- a/jooby/src/main/java/io/jooby/DefaultContext.java
+++ b/jooby/src/main/java/io/jooby/DefaultContext.java
@@ -452,6 +452,11 @@ default Value form(@NonNull String name) {
return form().get(name);
}
+ @Override
+ default Value form(@NonNull String name, @NonNull String defaultValue) {
+ return form().getOrDefault(name, defaultValue);
+ }
+
@Override
default T form(@NonNull Class type) {
return form().to(type);
diff --git a/jooby/src/main/java/io/jooby/ForwardingContext.java b/jooby/src/main/java/io/jooby/ForwardingContext.java
index 5d2a8fcfe6..f271c61d11 100644
--- a/jooby/src/main/java/io/jooby/ForwardingContext.java
+++ b/jooby/src/main/java/io/jooby/ForwardingContext.java
@@ -1001,6 +1001,11 @@ public Value form(@NonNull String name) {
return ctx.form(name);
}
+ @Override
+ public Value form(@NonNull String name, @NonNull String defaultValue) {
+ return ctx.form(name, defaultValue);
+ }
+
@Override
public T form(@NonNull Class type) {
return ctx.form(type);
diff --git a/modules/jooby-apt/src/test/java/tests/i3761/C3761.java b/modules/jooby-apt/src/test/java/tests/i3761/C3761.java
index ddca9bdaa3..578c5ee07d 100644
--- a/modules/jooby-apt/src/test/java/tests/i3761/C3761.java
+++ b/modules/jooby-apt/src/test/java/tests/i3761/C3761.java
@@ -5,6 +5,7 @@
*/
package tests.i3761;
+import io.jooby.annotation.FormParam;
import io.jooby.annotation.GET;
import io.jooby.annotation.Path;
import io.jooby.annotation.QueryParam;
@@ -31,4 +32,9 @@ public String emptySet(@QueryParam("") String emptySet) {
public String string(@QueryParam("Hello") String stringVal) {
return stringVal;
}
+
+ @GET("/boolVal")
+ public boolean bool(@FormParam("false") boolean boolVal) {
+ return boolVal;
+ }
}
diff --git a/modules/jooby-apt/src/test/java/tests/i3761/C3761Jakarta.java b/modules/jooby-apt/src/test/java/tests/i3761/C3761Jakarta.java
index 4802038a84..aadae957bd 100644
--- a/modules/jooby-apt/src/test/java/tests/i3761/C3761Jakarta.java
+++ b/modules/jooby-apt/src/test/java/tests/i3761/C3761Jakarta.java
@@ -9,6 +9,7 @@
import io.jooby.annotation.Path;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.FormParam;
@Path("/3761")
public class C3761Jakarta {
@@ -32,4 +33,9 @@ public String emptySet(@QueryParam("emptySet") @DefaultValue("") String emptySet
public String string(@QueryParam("stringVal") @DefaultValue("Hello") String stringVal) {
return stringVal;
}
+
+ @GET("/boolVal")
+ public boolean bool(@FormParam("boolVal") @DefaultValue("false") boolean boolVal) {
+ return boolVal;
+ }
}
diff --git a/modules/jooby-apt/src/test/java/tests/i3761/Issue3761.java b/modules/jooby-apt/src/test/java/tests/i3761/Issue3761.java
index 6a18f83c1b..963f350c74 100644
--- a/modules/jooby-apt/src/test/java/tests/i3761/Issue3761.java
+++ b/modules/jooby-apt/src/test/java/tests/i3761/Issue3761.java
@@ -30,5 +30,7 @@ private static void assertSourceCodeRespectDefaultValues(String source) {
source.contains("return c.emptySet(ctx.query(\"emptySet\", \"\").value());"));
assertTrue(
source.contains("return c.string(ctx.query(\"stringVal\", \"Hello\").value());"));
+ assertTrue(
+ source.contains("return c.bool(ctx.form(\"boolVal\", \"false\").booleanValue());"));
}
}