or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

basic-validation.mdcli.mdconfiguration.mdextensions.mdformat-validation.mdindex.mdsyntax-validation.md

format-validation.mddocs/

0

# Format Validation

1

2

Built-in format attribute validation for common data formats and extensible format validation system. Format validation provides semantic validation beyond basic JSON Schema types, ensuring data conforms to specific formats like email addresses, URIs, dates, and custom formats.

3

4

## Capabilities

5

6

### FormatAttribute Interface

7

8

Base interface for implementing format validation logic.

9

10

```java { .api }

11

/**

12

* Interface for implementing custom format validation

13

*/

14

public interface FormatAttribute {

15

/**

16

* Get supported JSON node types for this format

17

* @return EnumSet of NodeType values this format can validate

18

*/

19

EnumSet<NodeType> supportedTypes();

20

21

/**

22

* Validate format against instance data

23

* @param report ProcessingReport for collecting validation results

24

* @param bundle MessageBundle for error messages

25

* @param data FullData containing schema and instance information

26

* @throws ProcessingException if format validation processing fails

27

*/

28

void validate(ProcessingReport report, MessageBundle bundle, FullData data) throws ProcessingException;

29

}

30

31

/**

32

* Abstract base class providing common functionality for format attributes

33

*/

34

public abstract class AbstractFormatAttribute implements FormatAttribute {

35

/**

36

* Constructor with format name and supported types

37

* @param fmt Format name (e.g., "email", "date-time")

38

* @param first Required supported type

39

* @param other Additional supported types

40

*/

41

protected AbstractFormatAttribute(String fmt, NodeType first, NodeType... other);

42

43

/**

44

* Get format name

45

* @return String format name

46

*/

47

protected final String getFormatName();

48

49

/**

50

* Get supported node types

51

* @return EnumSet of supported NodeType values

52

*/

53

public final EnumSet<NodeType> supportedTypes();

54

55

/**

56

* Create new processing message for this format

57

* @param data Validation data

58

* @param bundle Message bundle

59

* @param key Message key

60

* @return ProcessingMessage for error reporting

61

*/

62

protected final ProcessingMessage newMsg(FullData data, MessageBundle bundle, String key);

63

}

64

```

65

66

### Built-in Format Attributes

67

68

#### Common Format Attributes

69

70

```java { .api }

71

/**

72

* Email format validation (RFC 5322)

73

*/

74

public final class EmailAttribute extends AbstractFormatAttribute {

75

public EmailAttribute();

76

}

77

78

/**

79

* URI format validation (RFC 3986)

80

*/

81

public final class URIAttribute extends AbstractFormatAttribute {

82

public URIAttribute();

83

}

84

85

/**

86

* Date-time format validation (RFC 3339)

87

*/

88

public final class DateTimeAttribute extends AbstractFormatAttribute {

89

public DateTimeAttribute();

90

}

91

92

/**

93

* Hostname format validation (RFC 1034)

94

*/

95

public final class HostnameAttribute extends AbstractFormatAttribute {

96

public HostnameAttribute();

97

}

98

99

/**

100

* IPv4 address format validation

101

*/

102

public final class IPv4Attribute extends AbstractFormatAttribute {

103

public IPv4Attribute();

104

}

105

106

/**

107

* IPv6 address format validation (RFC 4291)

108

*/

109

public final class IPv6Attribute extends AbstractFormatAttribute {

110

public IPv6Attribute();

111

}

112

113

/**

114

* Regular expression format validation

115

*/

116

public final class RegexAttribute extends AbstractFormatAttribute {

117

public RegexAttribute();

118

}

119

```

120

121

#### Draft v3 Specific Formats

122

123

```java { .api }

124

/**

125

* Date format validation (YYYY-MM-DD)

126

*/

127

public final class DateAttribute extends AbstractFormatAttribute {

128

public DateAttribute();

129

}

130

131

/**

132

* Time format validation (HH:MM:SS)

133

*/

134

public final class TimeAttribute extends AbstractFormatAttribute {

135

public TimeAttribute();

136

}

137

138

/**

139

* Phone number format validation

140

*/

141

public final class PhoneAttribute extends AbstractFormatAttribute {

142

public PhoneAttribute();

143

}

144

145

/**

146

* UTC milliseconds timestamp format validation

147

*/

148

public final class UTCMillisecAttribute extends AbstractFormatAttribute {

149

public UTCMillisecAttribute();

150

}

151

```

152

153

#### Extra Format Attributes

154

155

```java { .api }

156

/**

157

* Base64 encoded string format validation

158

*/

159

public final class Base64Attribute extends AbstractFormatAttribute {

160

public Base64Attribute();

161

}

162

163

/**

164

* Hexadecimal string format validation

165

*/

166

public final class HexStringAttribute extends AbstractFormatAttribute {

167

public HexStringAttribute();

168

}

169

170

/**

171

* UUID format validation (RFC 4122)

172

*/

173

public final class UUIDAttribute extends AbstractFormatAttribute {

174

public UUIDAttribute();

175

}

176

177

/**

178

* MD5 hash format validation

179

*/

180

public final class MD5Attribute extends AbstractFormatAttribute {

181

public MD5Attribute();

182

}

183

184

/**

185

* SHA1 hash format validation

186

*/

187

public final class SHA1Attribute extends AbstractFormatAttribute {

188

public SHA1Attribute();

189

}

190

191

/**

192

* SHA256 hash format validation

193

*/

194

public final class SHA256Attribute extends AbstractFormatAttribute {

195

public SHA256Attribute();

196

}

197

198

/**

199

* SHA512 hash format validation

200

*/

201

public final class SHA512Attribute extends AbstractFormatAttribute {

202

public SHA512Attribute();

203

}

204

```

205

206

### Format Dictionaries

207

208

Pre-built collections of format attributes for different JSON Schema versions.

209

210

```java { .api }

211

/**

212

* Common format attributes dictionary

213

*/

214

public final class CommonFormatAttributesDictionary {

215

/**

216

* Get dictionary of common format attributes

217

* @return Dictionary containing email, uri, datetime, hostname, ipv4, ipv6, regex formats

218

*/

219

public static Dictionary<FormatAttribute> get();

220

}

221

222

/**

223

* Draft v3 specific format attributes dictionary

224

*/

225

public final class DraftV3FormatAttributesDictionary {

226

/**

227

* Get dictionary of Draft v3 format attributes

228

* @return Dictionary containing date, time, phone, utc-millisec formats

229

*/

230

public static Dictionary<FormatAttribute> get();

231

}

232

233

/**

234

* Draft v4 format attributes dictionary

235

*/

236

public final class DraftV4FormatAttributesDictionary {

237

/**

238

* Get dictionary of Draft v4 format attributes

239

* @return Dictionary containing common formats for Draft v4

240

*/

241

public static Dictionary<FormatAttribute> get();

242

}

243

244

/**

245

* Extra format attributes dictionary

246

*/

247

public final class ExtraFormatsDictionary {

248

/**

249

* Get dictionary of additional format attributes

250

* @return Dictionary containing base64, hex, uuid, md5, sha1, sha256, sha512 formats

251

*/

252

public static Dictionary<FormatAttribute> get();

253

}

254

```

255

256

## Usage Examples

257

258

### Example 1: Using Built-in Format Validation

259

260

```java

261

import com.github.fge.jsonschema.cfg.ValidationConfiguration;

262

import com.github.fge.jsonschema.main.JsonSchemaFactory;

263

import com.fasterxml.jackson.databind.JsonNode;

264

import com.fasterxml.jackson.databind.ObjectMapper;

265

266

// Enable format validation (disabled by default for performance)

267

ValidationConfiguration config = ValidationConfiguration.newBuilder()

268

.setUseFormat(true)

269

.freeze();

270

271

JsonSchemaFactory factory = JsonSchemaFactory.newBuilder()

272

.setValidationConfiguration(config)

273

.freeze();

274

275

// Schema with format constraints

276

ObjectMapper mapper = new ObjectMapper();

277

JsonNode schema = mapper.readTree("{\n" +

278

" \"type\": \"object\",\n" +

279

" \"properties\": {\n" +

280

" \"email\": {\n" +

281

" \"type\": \"string\",\n" +

282

" \"format\": \"email\"\n" +

283

" },\n" +

284

" \"website\": {\n" +

285

" \"type\": \"string\",\n" +

286

" \"format\": \"uri\"\n" +

287

" },\n" +

288

" \"birthdate\": {\n" +

289

" \"type\": \"string\",\n" +

290

" \"format\": \"date-time\"\n" +

291

" },\n" +

292

" \"server\": {\n" +

293

" \"type\": \"string\",\n" +

294

" \"format\": \"hostname\"\n" +

295

" }\n" +

296

" }\n" +

297

"}");

298

299

JsonSchema jsonSchema = factory.getJsonSchema(schema);

300

301

// Valid instance

302

JsonNode validInstance = mapper.readTree("{\n" +

303

" \"email\": \"user@example.com\",\n" +

304

" \"website\": \"https://example.com\",\n" +

305

" \"birthdate\": \"1990-01-15T08:30:00Z\",\n" +

306

" \"server\": \"api.example.com\"\n" +

307

"}");

308

309

ProcessingReport validReport = jsonSchema.validate(validInstance);

310

System.out.println("Valid: " + validReport.isSuccess()); // true

311

312

// Invalid instance with format errors

313

JsonNode invalidInstance = mapper.readTree("{\n" +

314

" \"email\": \"invalid-email\",\n" +

315

" \"website\": \"not-a-uri\",\n" +

316

" \"birthdate\": \"invalid-date\",\n" +

317

" \"server\": \"invalid_hostname\"\n" +

318

"}");

319

320

ProcessingReport invalidReport = jsonSchema.validate(invalidInstance);

321

if (!invalidReport.isSuccess()) {

322

System.out.println("Format validation errors:");

323

for (ProcessingMessage message : invalidReport) {

324

System.out.println(" " + message.getMessage());

325

}

326

}

327

```

328

329

### Example 2: Custom Format Attribute

330

331

```java

332

import com.github.fge.jsonschema.format.AbstractFormatAttribute;

333

import com.github.fge.jsonschema.core.report.ProcessingReport;

334

import com.github.fge.jsonschema.processors.data.FullData;

335

336

/**

337

* Custom format attribute for validating ISBN numbers

338

*/

339

public final class ISBNFormatAttribute extends AbstractFormatAttribute {

340

private static final String FORMAT_NAME = "isbn";

341

342

public ISBNFormatAttribute() {

343

super(FORMAT_NAME, NodeType.STRING);

344

}

345

346

@Override

347

public void validate(ProcessingReport report, MessageBundle bundle,

348

FullData data) throws ProcessingException {

349

350

JsonNode instance = data.getInstance().getNode();

351

String isbn = instance.asText();

352

353

if (!isValidISBN(isbn)) {

354

ProcessingMessage message = newMsg(data, bundle, "err.format.isbn")

355

.putArgument("value", isbn);

356

report.error(message);

357

}

358

}

359

360

private boolean isValidISBN(String isbn) {

361

// Remove hyphens and spaces

362

String cleanISBN = isbn.replaceAll("[\\s-]", "");

363

364

// Check ISBN-10 or ISBN-13

365

return isValidISBN10(cleanISBN) || isValidISBN13(cleanISBN);

366

}

367

368

private boolean isValidISBN10(String isbn) {

369

if (isbn.length() != 10) return false;

370

371

int sum = 0;

372

for (int i = 0; i < 9; i++) {

373

if (!Character.isDigit(isbn.charAt(i))) return false;

374

sum += (isbn.charAt(i) - '0') * (10 - i);

375

}

376

377

char checkChar = isbn.charAt(9);

378

int checkDigit = (checkChar == 'X') ? 10 : Character.getNumericValue(checkChar);

379

380

return (sum + checkDigit) % 11 == 0;

381

}

382

383

private boolean isValidISBN13(String isbn) {

384

if (isbn.length() != 13) return false;

385

386

int sum = 0;

387

for (int i = 0; i < 12; i++) {

388

if (!Character.isDigit(isbn.charAt(i))) return false;

389

int digit = isbn.charAt(i) - '0';

390

sum += (i % 2 == 0) ? digit : digit * 3;

391

}

392

393

int checkDigit = Character.getNumericValue(isbn.charAt(12));

394

return (sum + checkDigit) % 10 == 0;

395

}

396

}

397

398

// Register custom format attribute

399

Library customLibrary = DraftV4Library.get().thaw()

400

.addFormatAttribute("isbn", new ISBNFormatAttribute())

401

.freeze();

402

403

ValidationConfiguration config = ValidationConfiguration.newBuilder()

404

.addLibrary("http://json-schema.org/draft-04/schema#", customLibrary)

405

.setUseFormat(true)

406

.freeze();

407

408

JsonSchemaFactory factory = JsonSchemaFactory.newBuilder()

409

.setValidationConfiguration(config)

410

.freeze();

411

412

// Use custom format in schema

413

String schemaWithISBN = "{\n" +

414

" \"type\": \"object\",\n" +

415

" \"properties\": {\n" +

416

" \"book_isbn\": {\n" +

417

" \"type\": \"string\",\n" +

418

" \"format\": \"isbn\"\n" +

419

" }\n" +

420

" }\n" +

421

"}";

422

```

423

424

### Example 3: Format Validation Service

425

426

```java

427

/**

428

* Service for format validation with multiple format libraries

429

*/

430

public class FormatValidationService {

431

private final JsonSchemaFactory standardFactory;

432

private final JsonSchemaFactory extendedFactory;

433

434

public FormatValidationService() {

435

// Standard factory with built-in formats

436

ValidationConfiguration standardConfig = ValidationConfiguration.newBuilder()

437

.setUseFormat(true)

438

.freeze();

439

this.standardFactory = JsonSchemaFactory.newBuilder()

440

.setValidationConfiguration(standardConfig)

441

.freeze();

442

443

// Extended factory with additional formats

444

Library extendedLibrary = DraftV4Library.get().thaw()

445

.addFormatAttribute("isbn", new ISBNFormatAttribute())

446

.addFormatAttribute("credit-card", new CreditCardFormatAttribute())

447

.addFormatAttribute("iban", new IBANFormatAttribute())

448

.freeze();

449

450

ValidationConfiguration extendedConfig = ValidationConfiguration.newBuilder()

451

.addLibrary("http://json-schema.org/draft-04/schema#", extendedLibrary)

452

.setUseFormat(true)

453

.freeze();

454

455

this.extendedFactory = JsonSchemaFactory.newBuilder()

456

.setValidationConfiguration(extendedConfig)

457

.freeze();

458

}

459

460

public ProcessingReport validateWithStandardFormats(JsonNode schema, JsonNode instance) throws ProcessingException {

461

JsonSchema jsonSchema = standardFactory.getJsonSchema(schema);

462

return jsonSchema.validate(instance);

463

}

464

465

public ProcessingReport validateWithExtendedFormats(JsonNode schema, JsonNode instance) throws ProcessingException {

466

JsonSchema jsonSchema = extendedFactory.getJsonSchema(schema);

467

return jsonSchema.validate(instance);

468

}

469

470

public List<String> getSupportedFormats(boolean includeExtended) {

471

List<String> formats = Arrays.asList(

472

"email", "uri", "date-time", "hostname", "ipv4", "ipv6", "regex"

473

);

474

475

if (includeExtended) {

476

List<String> extended = new ArrayList<>(formats);

477

extended.addAll(Arrays.asList("isbn", "credit-card", "iban", "base64", "uuid"));

478

return extended;

479

}

480

481

return formats;

482

}

483

}

484

```

485

486

### Example 4: Conditional Format Validation

487

488

```java

489

/**

490

* Format validator with conditional validation logic

491

*/

492

public final class ConditionalEmailAttribute extends AbstractFormatAttribute {

493

public ConditionalEmailAttribute() {

494

super("conditional-email", NodeType.STRING);

495

}

496

497

@Override

498

public void validate(ProcessingReport report, MessageBundle bundle,

499

FullData data) throws ProcessingException {

500

501

JsonNode instance = data.getInstance().getNode();

502

JsonNode schema = data.getSchema().getNode();

503

String email = instance.asText();

504

505

// Check if strict validation is enabled in schema

506

boolean strictMode = schema.path("strictEmail").asBoolean(false);

507

508

if (strictMode) {

509

validateStrictEmail(email, report, bundle, data);

510

} else {

511

validateBasicEmail(email, report, bundle, data);

512

}

513

}

514

515

private void validateStrictEmail(String email, ProcessingReport report,

516

MessageBundle bundle, FullData data) throws ProcessingException {

517

// Strict RFC 5322 validation

518

if (!email.matches("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$")) {

519

ProcessingMessage message = newMsg(data, bundle, "err.format.email.strict")

520

.putArgument("value", email);

521

report.error(message);

522

}

523

}

524

525

private void validateBasicEmail(String email, ProcessingReport report,

526

MessageBundle bundle, FullData data) throws ProcessingException {

527

// Basic email validation

528

if (!email.contains("@") || !email.contains(".")) {

529

ProcessingMessage message = newMsg(data, bundle, "err.format.email.basic")

530

.putArgument("value", email);

531

report.error(message);

532

}

533

}

534

}

535

536

// Usage in schema

537

String conditionalSchema = "{\n" +

538

" \"type\": \"object\",\n" +

539

" \"properties\": {\n" +

540

" \"email\": {\n" +

541

" \"type\": \"string\",\n" +

542

" \"format\": \"conditional-email\",\n" +

543

" \"strictEmail\": true\n" +

544

" }\n" +

545

" }\n" +

546

"}";

547

```

548

549

## Available Format Attributes

550

551

### Common Formats (always available)

552

- `email` - Email addresses (RFC 5322)

553

- `uri` - Uniform Resource Identifiers (RFC 3986)

554

- `date-time` - Date and time (RFC 3339)

555

- `hostname` - Internet hostnames (RFC 1034)

556

- `ipv4` - IPv4 addresses

557

- `ipv6` - IPv6 addresses (RFC 4291)

558

- `regex` - Regular expressions

559

560

### Draft v3 Specific Formats

561

- `date` - Date in YYYY-MM-DD format

562

- `time` - Time in HH:MM:SS format

563

- `phone` - Phone number validation

564

- `utc-millisec` - UTC milliseconds timestamp

565

566

### Extra Formats (available via ExtraFormatsDictionary)

567

- `base64` - Base64 encoded strings

568

- `hex` - Hexadecimal strings

569

- `uuid` - UUID strings (RFC 4122)

570

- `md5` - MD5 hash strings

571

- `sha1` - SHA1 hash strings

572

- `sha256` - SHA256 hash strings

573

- `sha512` - SHA512 hash strings

574

575

## Best Practices

576

577

1. **Performance**: Enable format validation only when needed (`setUseFormat(true)`)

578

2. **Extensibility**: Create custom formats for domain-specific validation requirements

579

3. **Error Messages**: Provide clear, actionable error messages in custom formats

580

4. **Type Safety**: Use appropriate NodeType constraints in format attributes

581

5. **Validation Logic**: Keep format validation focused and efficient

582

6. **Testing**: Thoroughly test custom formats with valid and invalid inputs

583

7. **Standards Compliance**: Follow relevant RFCs and standards for format validation