or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

dependency-injection.mdform-processing.mdformatting.mdindex.mdrouting.mdstreaming.mdutilities.mdvalidation.md

form-processing.mddocs/

0

# Form Processing

1

2

Play Framework's form processing capabilities provide comprehensive support for handling HTML forms, data binding, and form field management. The system supports both dynamic forms for unstructured data and typed forms for model binding with automatic type conversion.

3

4

## Capabilities

5

6

### Dynamic Form Handling

7

8

Dynamic forms handle unstructured form data using a HashMap-backed approach, ideal for forms with variable fields or when you don't have a predefined model.

9

10

```java { .api }

11

/**

12

* Dynamic form backed by HashMap for unstructured data binding

13

*/

14

public class DynamicForm extends Form<DynamicForm.Dynamic> {

15

/** Create empty dynamic form */

16

public DynamicForm();

17

18

/** Create dynamic form with data and errors */

19

public DynamicForm(Map<String,String> data, Map<String,List<ValidationError>> errors, Option<Dynamic> value);

20

21

/** Get field value by key */

22

public String get(String key);

23

24

/** Get all form data as map */

25

public Map<String, String> data();

26

27

/** Fill form with existing data */

28

public DynamicForm fill(Map value);

29

30

/** Bind form from HTTP request */

31

public DynamicForm bindFromRequest(String... allowedFields);

32

33

/** Bind form from data map */

34

public DynamicForm bind(Map<String,String> data, String... allowedFields);

35

36

/** Get field wrapper by key */

37

public Form.Field field(String key);

38

39

/** Get validation error for field */

40

public ValidationError error(String key);

41

42

/** Add validation error */

43

public void reject(String key, String error, List<Object> args);

44

45

/** Convert key to dynamic form key format */

46

static String asDynamicKey(String key);

47

48

/** Convert dynamic form key to normal key format */

49

static String asNormalKey(String key);

50

}

51

52

/**

53

* Data structure for dynamic form data

54

*/

55

public static class DynamicForm.Dynamic {

56

/** Default constructor */

57

public Dynamic();

58

59

/** Constructor with initial data */

60

public Dynamic(Map data);

61

62

/** Get underlying data map */

63

public Map getData();

64

65

/** Set data map */

66

public void setData(Map data);

67

}

68

```

69

70

**Usage Examples:**

71

72

```java

73

import play.data.Form;

74

import play.data.DynamicForm;

75

76

// Create and bind dynamic form

77

public Result handleContactForm() {

78

DynamicForm contactForm = Form.form().bindFromRequest();

79

80

if (contactForm.hasErrors()) {

81

return badRequest(contactForm.errorsAsJson());

82

}

83

84

String name = contactForm.get("name");

85

String email = contactForm.get("email");

86

String message = contactForm.get("message");

87

88

// Process form data

89

return ok("Thank you " + name + "! We'll contact you at " + email);

90

}

91

92

// Pre-fill dynamic form

93

public Result editSettings() {

94

Map<String, String> existingData = new HashMap<>();

95

existingData.put("theme", "dark");

96

existingData.put("language", "en");

97

98

DynamicForm settingsForm = Form.form().fill(existingData);

99

return ok(views.html.settings.render(settingsForm));

100

}

101

```

102

103

### Typed Form Handling

104

105

Typed forms provide strong type safety by binding form data directly to Java model classes with automatic validation and type conversion.

106

107

```java { .api }

108

/**

109

* Helper to manage HTML form description, submission and validation

110

*/

111

public class Form<T> {

112

/** Create dynamic form */

113

public static DynamicForm form();

114

115

/** Create typed form for given class */

116

public static <T> Form<T> form(Class<T> clazz);

117

118

/** Create named typed form */

119

public static <T> Form<T> form(String name, Class<T> clazz);

120

121

/** Create typed form with validation group */

122

public static <T> Form<T> form(String name, Class<T> clazz, Class<?> group);

123

124

/** Bind form from HTTP request */

125

public Form<T> bindFromRequest(String... allowedFields);

126

127

/** Bind form from HTTP request with explicit request object */

128

public Form<T> bindFromRequest(Http.Request request, String... allowedFields);

129

130

/** Bind form from request data map */

131

public Form<T> bindFromRequest(Map<String,String[]> requestData, String... allowedFields);

132

133

/** Bind form from data map */

134

public Form<T> bind(Map<String,String> data, String... allowedFields);

135

136

/** Bind form from JSON data */

137

public Form<T> bind(com.fasterxml.jackson.databind.JsonNode data, String... allowedFields);

138

139

/** Fill form with existing model instance */

140

public Form<T> fill(T value);

141

142

/** Get form data as string map */

143

public Map<String,String> data();

144

145

/** Get typed form value if no errors */

146

public Option<T> value();

147

148

/** Get form value, throws if errors exist */

149

public T get();

150

151

/** Check if form has any validation errors */

152

public boolean hasErrors();

153

154

/** Check if form has global (non-field) errors */

155

public boolean hasGlobalErrors();

156

157

/** Get all global errors */

158

public List<ValidationError> globalErrors();

159

160

/** Get single global error (null if none) */

161

public ValidationError globalError();

162

163

/** Get all validation errors */

164

public Map<String,List<ValidationError>> errors();

165

166

/** Get errors as JSON */

167

public com.fasterxml.jackson.databind.JsonNode errorsAsJson();

168

169

/** Get errors as JSON with specific language */

170

public com.fasterxml.jackson.databind.JsonNode errorsAsJson(play.i18n.Lang lang);

171

172

/** Get field wrapper by key */

173

public Field field(String key);

174

175

/** Get field wrapper by key (alias for field) */

176

public Field apply(String key);

177

178

/** Get form name */

179

public String name();

180

181

/** Discard errors and return clean form */

182

public Form<T> discardErrors();

183

184

/** Add global validation error */

185

public void reject(String error);

186

187

/** Add field-specific validation error */

188

public void reject(String key, String error);

189

}

190

```

191

192

**Usage Examples:**

193

194

```java

195

import play.data.Form;

196

import play.data.validation.Constraints.*;

197

198

// Model class with validation annotations

199

public class User {

200

@Required

201

@MinLength(2)

202

public String name;

203

204

@Required

205

@Email

206

public String email;

207

208

@Min(18)

209

public Integer age;

210

211

public String bio;

212

}

213

214

// Controller using typed form

215

public class UserController extends Controller {

216

217

public Result showCreateForm() {

218

Form<User> userForm = Form.form(User.class);

219

return ok(views.html.createUser.render(userForm));

220

}

221

222

public Result createUser() {

223

Form<User> userForm = Form.form(User.class).bindFromRequest();

224

225

if (userForm.hasErrors()) {

226

return badRequest(views.html.createUser.render(userForm));

227

}

228

229

User user = userForm.get();

230

// Save user to database

231

userRepository.save(user);

232

233

return redirect(routes.UserController.showUser(user.id));

234

}

235

236

public Result editUser(Long id) {

237

User existingUser = userRepository.findById(id);

238

Form<User> userForm = Form.form(User.class).fill(existingUser);

239

return ok(views.html.editUser.render(userForm));

240

}

241

}

242

```

243

244

### Form Field Management

245

246

Form fields provide detailed access to field values, validation errors, and metadata.

247

248

```java { .api }

249

/**

250

* Represents a form field with value and validation information

251

*/

252

public static class Form.Field {

253

/** Get field name */

254

public String name();

255

256

/** Get field value */

257

public String value();

258

259

/** Get field value or default if empty */

260

public String valueOr(String or);

261

262

/** Get validation errors for this field */

263

public List<ValidationError> errors();

264

265

/** Get field constraints */

266

public List<Tuple<String,List<Object>>> constraints();

267

268

/** Get field format information */

269

public Tuple<String,List<Object>> format();

270

271

/** Get indexes for repeated fields */

272

public List<Integer> indexes();

273

274

/** Get sub-field by key */

275

public Field sub(String key);

276

}

277

```

278

279

### Form Display Configuration

280

281

Configure form element display names and attributes using annotations.

282

283

```java { .api }

284

/**

285

* Annotation to define display properties for form elements

286

*/

287

@interface Form.Display {

288

/** Display name for the field */

289

String name();

290

291

/** Additional display attributes */

292

String[] attributes() default {};

293

}

294

```

295

296

**Usage Examples:**

297

298

```java

299

public class Product {

300

@Form.Display(name = "Product Name")

301

@Required

302

public String name;

303

304

@Form.Display(name = "Price (USD)", attributes = {"currency", "decimal"})

305

@Min(0)

306

public BigDecimal price;

307

}

308

309

// Accessing field information in templates

310

public Result showProductForm() {

311

Form<Product> productForm = Form.form(Product.class);

312

Form.Field nameField = productForm.field("name");

313

314

String displayName = nameField.name(); // Gets display name from annotation

315

List<ValidationError> errors = nameField.errors();

316

317

return ok(views.html.productForm.render(productForm));

318

}

319

```

320

321

## Advanced Usage Patterns

322

323

### Partial Field Binding

324

325

Control which fields are bound from requests for security and data integrity.

326

327

```java

328

// Only bind specific fields from request

329

Form<User> userForm = Form.form(User.class)

330

.bindFromRequest("name", "email"); // Only these fields will be bound

331

332

// Useful for preventing mass assignment vulnerabilities

333

Form<User> userForm = Form.form(User.class)

334

.bindFromRequest("name", "email", "bio"); // Admin fields excluded

335

```

336

337

### JSON Data Binding

338

339

Bind forms directly from JSON data for API endpoints.

340

341

```java

342

public Result createUserFromJson() {

343

JsonNode json = request().body().asJson();

344

Form<User> userForm = Form.form(User.class).bind(json);

345

346

if (userForm.hasErrors()) {

347

return badRequest(userForm.errorsAsJson());

348

}

349

350

User user = userForm.get();

351

return created(Json.toJson(user));

352

}

353

```

354

355

### Custom Error Handling

356

357

Add custom validation errors programmatically.

358

359

```java

360

public Result validateUser() {

361

Form<User> userForm = Form.form(User.class).bindFromRequest();

362

363

// Custom validation logic

364

if (userService.emailExists(userForm.field("email").value())) {

365

userForm.reject("email", "This email is already registered");

366

}

367

368

if (userForm.hasErrors()) {

369

return badRequest(views.html.createUser.render(userForm));

370

}

371

372

return ok("User is valid");

373

}

374

```