or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

caching-loading.mdcore-processing.mdexception-handling.mdextensions.mdindex.mdobject-wrapping.mdoutput-formats.mdtemplate-models.md

template-models.mddocs/

0

# Template Model System

1

2

The template model system provides interfaces for representing different data types in FreeMarker templates. These interfaces enable seamless integration between Java objects and template expressions.

3

4

## Core Model Interfaces

5

6

### Base Interface

7

8

```java { .api }

9

interface TemplateModel {

10

// Singleton constant representing null/empty values

11

TemplateModel NOTHING = GeneralPurposeNothing.INSTANCE;

12

}

13

```

14

15

All template model interfaces extend this base interface. The `NOTHING` constant represents null or empty values in templates.

16

17

### Scalar Models (Strings)

18

19

```java { .api }

20

interface TemplateScalarModel extends TemplateModel {

21

String getAsString() throws TemplateModelException;

22

}

23

24

// Simple implementation

25

class SimpleScalar implements TemplateScalarModel {

26

SimpleScalar(String value);

27

String getAsString() throws TemplateModelException;

28

}

29

```

30

31

Usage example:

32

```java

33

TemplateModel stringValue = new SimpleScalar("Hello World");

34

// In template: ${stringValue} outputs "Hello World"

35

```

36

37

### Number Models

38

39

```java { .api }

40

interface TemplateNumberModel extends TemplateModel {

41

Number getAsNumber() throws TemplateModelException;

42

}

43

44

// Simple implementation

45

class SimpleNumber implements TemplateNumberModel {

46

SimpleNumber(Number value);

47

Number getAsNumber() throws TemplateModelException;

48

}

49

```

50

51

Usage example:

52

```java

53

TemplateModel numberValue = new SimpleNumber(42);

54

// In template: ${numberValue} outputs "42"

55

// In template: ${numberValue + 8} outputs "50"

56

```

57

58

### Boolean Models

59

60

```java { .api }

61

interface TemplateBooleanModel extends TemplateModel {

62

boolean getAsBoolean() throws TemplateModelException;

63

64

// Predefined constants

65

TemplateBooleanModel TRUE = TrueBooleanModel.INSTANCE;

66

TemplateBooleanModel FALSE = FalseBooleanModel.INSTANCE;

67

}

68

69

// True implementation

70

class TrueBooleanModel implements TemplateBooleanModel {

71

static final TrueBooleanModel INSTANCE = new TrueBooleanModel();

72

boolean getAsBoolean() throws TemplateModelException;

73

}

74

75

// False implementation

76

class FalseBooleanModel implements TemplateBooleanModel {

77

static final FalseBooleanModel INSTANCE = new FalseBooleanModel();

78

boolean getAsBoolean() throws TemplateModelException;

79

}

80

```

81

82

Usage example:

83

```java

84

TemplateModel isActive = TemplateBooleanModel.TRUE;

85

// In template: <#if isActive>Active</#if>

86

```

87

88

### Date Models

89

90

```java { .api }

91

interface TemplateDateModel extends TemplateModel {

92

Date getAsDate() throws TemplateModelException;

93

int getDateType();

94

95

// Date type constants

96

int DATE = 1; // Date only (no time)

97

int TIME = 2; // Time only (no date)

98

int DATETIME = 3; // Both date and time

99

int UNKNOWN = 0; // Unknown date type

100

}

101

102

// Simple implementation

103

class SimpleDate implements TemplateDateModel {

104

SimpleDate(Date date, int type);

105

Date getAsDate() throws TemplateModelException;

106

int getDateType();

107

}

108

```

109

110

Usage example:

111

```java

112

TemplateModel currentDate = new SimpleDate(new Date(), TemplateDateModel.DATETIME);

113

// In template: ${currentDate?string("yyyy-MM-dd HH:mm:ss")}

114

```

115

116

## Collection Models

117

118

### Sequence Models (Lists/Arrays)

119

120

```java { .api }

121

interface TemplateSequenceModel extends TemplateModel {

122

TemplateModel get(int index) throws TemplateModelException;

123

int size() throws TemplateModelException;

124

}

125

126

// Simple implementation

127

class SimpleSequence extends WrappingTemplateModel implements TemplateSequenceModel {

128

SimpleSequence();

129

SimpleSequence(ObjectWrapper wrapper);

130

SimpleSequence(Collection collection, ObjectWrapper wrapper);

131

132

void add(Object obj);

133

TemplateModel get(int index) throws TemplateModelException;

134

int size() throws TemplateModelException;

135

List toList() throws TemplateModelException;

136

}

137

```

138

139

Usage example:

140

```java

141

SimpleSequence items = new SimpleSequence();

142

items.add("Apple");

143

items.add("Banana");

144

items.add("Cherry");

145

// In template: <#list items as item>${item}</#list>

146

```

147

148

### Hash Models (Maps/Objects)

149

150

```java { .api }

151

interface TemplateHashModel extends TemplateModel {

152

TemplateModel get(String key) throws TemplateModelException;

153

boolean isEmpty() throws TemplateModelException;

154

}

155

156

// Extended hash model with iteration capabilities

157

interface TemplateHashModelEx extends TemplateHashModel {

158

TemplateCollectionModel keys() throws TemplateModelException;

159

TemplateCollectionModel values() throws TemplateModelException;

160

int size() throws TemplateModelException;

161

}

162

163

// Enhanced hash model with key-value iteration

164

interface TemplateHashModelEx2 extends TemplateHashModelEx {

165

KeyValuePairIterator keyValuePairIterator() throws TemplateModelException;

166

}

167

168

// Simple implementation

169

class SimpleHash extends WrappingTemplateModel implements TemplateHashModelEx2 {

170

SimpleHash();

171

SimpleHash(ObjectWrapper wrapper);

172

SimpleHash(Map map, ObjectWrapper wrapper);

173

174

void put(String key, Object value);

175

void put(String key, boolean value);

176

void put(String key, Number value);

177

void remove(String key);

178

void clear();

179

180

TemplateModel get(String key) throws TemplateModelException;

181

boolean isEmpty() throws TemplateModelException;

182

int size() throws TemplateModelException;

183

TemplateCollectionModel keys() throws TemplateModelException;

184

TemplateCollectionModel values() throws TemplateModelException;

185

KeyValuePairIterator keyValuePairIterator() throws TemplateModelException;

186

}

187

```

188

189

Usage example:

190

```java

191

SimpleHash person = new SimpleHash();

192

person.put("name", "John Doe");

193

person.put("age", 30);

194

person.put("active", true);

195

// In template: ${person.name} is ${person.age} years old

196

```

197

198

### Collection Models (Iteration)

199

200

```java { .api }

201

interface TemplateCollectionModel extends TemplateModel {

202

TemplateModelIterator iterator() throws TemplateModelException;

203

}

204

205

// Extended collection with size information

206

interface TemplateCollectionModelEx extends TemplateCollectionModel {

207

int size() throws TemplateModelException;

208

}

209

210

// Simple implementation

211

class SimpleCollection extends WrappingTemplateModel implements TemplateCollectionModelEx {

212

SimpleCollection(Collection collection);

213

SimpleCollection(Collection collection, ObjectWrapper wrapper);

214

SimpleCollection(Iterator iterator);

215

SimpleCollection(Iterator iterator, ObjectWrapper wrapper);

216

217

TemplateModelIterator iterator() throws TemplateModelException;

218

int size() throws TemplateModelException;

219

}

220

```

221

222

## Functional Models

223

224

### Method Models

225

226

```java { .api }

227

interface TemplateMethodModel extends TemplateModel {

228

Object exec(List arguments) throws TemplateModelException;

229

}

230

231

// Enhanced method model with TemplateModel arguments

232

interface TemplateMethodModelEx extends TemplateMethodModel {

233

Object exec(List arguments) throws TemplateModelException;

234

}

235

```

236

237

Usage example:

238

```java

239

TemplateMethodModelEx upperCase = new TemplateMethodModelEx() {

240

public Object exec(List arguments) throws TemplateModelException {

241

if (arguments.size() != 1) {

242

throw new TemplateModelException("Wrong number of arguments");

243

}

244

String s = ((TemplateScalarModel) arguments.get(0)).getAsString();

245

return new SimpleScalar(s.toUpperCase());

246

}

247

};

248

// In template: ${upperCase("hello")} outputs "HELLO"

249

```

250

251

### Directive Models

252

253

```java { .api }

254

interface TemplateDirectiveModel extends TemplateModel {

255

void execute(Environment env, Map params, TemplateModel[] loopVars,

256

TemplateDirectiveBody body) throws TemplateException, IOException;

257

}

258

259

// Body interface for directive content

260

interface TemplateDirectiveBody {

261

void render(Writer out) throws TemplateException, IOException;

262

}

263

```

264

265

Usage example:

266

```java

267

TemplateDirectiveModel repeat = new TemplateDirectiveModel() {

268

public void execute(Environment env, Map params, TemplateModel[] loopVars,

269

TemplateDirectiveBody body) throws TemplateException, IOException {

270

int count = ((TemplateNumberModel) params.get("count")).getAsNumber().intValue();

271

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

272

loopVars[0] = new SimpleNumber(i);

273

body.render(env.getOut());

274

}

275

}

276

};

277

// In template: <@repeat count=3 ; i>Item ${i}</@repeat>

278

```

279

280

### Transform Models

281

282

```java { .api }

283

interface TemplateTransformModel extends TemplateModel {

284

Writer getWriter(Writer out, Map args) throws TemplateModelException, IOException;

285

}

286

```

287

288

Usage example:

289

```java

290

TemplateTransformModel upperCaseTransform = new TemplateTransformModel() {

291

public Writer getWriter(Writer out, Map args) throws TemplateModelException, IOException {

292

return new FilterWriter(out) {

293

public void write(String str) throws IOException {

294

out.write(str.toUpperCase());

295

}

296

};

297

}

298

};

299

// In template: <@upperCaseTransform>hello world</@upperCaseTransform>

300

```

301

302

## Node Models (XML/Tree Structures)

303

304

```java { .api }

305

interface TemplateNodeModel extends TemplateModel {

306

TemplateModel get(String key) throws TemplateModelException;

307

TemplateSequenceModel getChildNodes() throws TemplateModelException;

308

String getNodeName() throws TemplateModelException;

309

String getNodeType() throws TemplateModelException;

310

TemplateNodeModel getParentNode() throws TemplateModelException;

311

}

312

313

// Extended node model with namespace support

314

interface TemplateNodeModelEx extends TemplateNodeModel {

315

String getNodeNamespace() throws TemplateModelException;

316

String getNamespaceURI(String prefix) throws TemplateModelException;

317

}

318

```

319

320

## Iteration Support

321

322

```java { .api }

323

interface TemplateModelIterator {

324

TemplateModel next() throws TemplateModelException;

325

boolean hasNext() throws TemplateModelException;

326

}

327

328

interface KeyValuePairIterator {

329

KeyValuePair next() throws TemplateModelException;

330

boolean hasNext() throws TemplateModelException;

331

}

332

333

interface KeyValuePair {

334

TemplateModel getKey() throws TemplateModelException;

335

TemplateModel getValue() throws TemplateModelException;

336

}

337

```

338

339

## Adapter Classes

340

341

### Collection Adapters

342

343

```java { .api }

344

class DefaultListAdapter extends WrappingTemplateModel implements TemplateSequenceModel, AdapterTemplateModel {

345

DefaultListAdapter(List list, ObjectWrapper wrapper);

346

TemplateModel get(int index) throws TemplateModelException;

347

int size() throws TemplateModelException;

348

Object getAdaptedObject(Class hint);

349

}

350

351

class DefaultMapAdapter extends WrappingTemplateModel implements TemplateHashModelEx2, AdapterTemplateModel {

352

DefaultMapAdapter(Map map, ObjectWrapper wrapper);

353

TemplateModel get(String key) throws TemplateModelException;

354

boolean isEmpty() throws TemplateModelException;

355

int size() throws TemplateModelException;

356

TemplateCollectionModel keys() throws TemplateModelException;

357

TemplateCollectionModel values() throws TemplateModelException;

358

Object getAdaptedObject(Class hint);

359

}

360

361

class DefaultArrayAdapter extends WrappingTemplateModel implements TemplateSequenceModel, AdapterTemplateModel {

362

DefaultArrayAdapter(Object array, ObjectWrapper wrapper);

363

TemplateModel get(int index) throws TemplateModelException;

364

int size() throws TemplateModelException;

365

Object getAdaptedObject(Class hint);

366

}

367

```

368

369

### Iterator Adapters

370

371

```java { .api }

372

class DefaultIteratorAdapter extends WrappingTemplateModel implements TemplateCollectionModel, AdapterTemplateModel {

373

DefaultIteratorAdapter(Iterator iterator, ObjectWrapper wrapper);

374

TemplateModelIterator iterator() throws TemplateModelException;

375

Object getAdaptedObject(Class hint);

376

}

377

378

class DefaultEnumerationAdapter extends WrappingTemplateModel implements TemplateCollectionModel, AdapterTemplateModel {

379

DefaultEnumerationAdapter(Enumeration enumeration, ObjectWrapper wrapper);

380

TemplateModelIterator iterator() throws TemplateModelException;

381

Object getAdaptedObject(Class hint);

382

}

383

```

384

385

## Utility Classes

386

387

```java { .api }

388

abstract class WrappingTemplateModel implements TemplateModel, AdapterTemplateModel {

389

WrappingTemplateModel(ObjectWrapper objectWrapper);

390

ObjectWrapper getObjectWrapper();

391

TemplateModel wrap(Object obj) throws TemplateModelException;

392

}

393

394

// Represents null/nothing values

395

class GeneralPurposeNothing implements TemplateModel {

396

static final GeneralPurposeNothing INSTANCE = new GeneralPurposeNothing();

397

}

398

399

// For wrapping objects that implement multiple model interfaces

400

interface AdapterTemplateModel extends TemplateModel {

401

Object getAdaptedObject(Class hint);

402

}

403

```

404

405

## Model Creation Best Practices

406

407

### Using Simple Model Classes

408

409

For basic use cases, use the Simple* classes:

410

411

```java

412

// Create simple models

413

Map<String, Object> dataModel = new HashMap<>();

414

dataModel.put("title", "My Page"); // Auto-wrapped to SimpleScalar

415

dataModel.put("count", 42); // Auto-wrapped to SimpleNumber

416

dataModel.put("active", true); // Auto-wrapped to TrueBooleanModel

417

418

// Or create explicitly

419

dataModel.put("message", new SimpleScalar("Hello"));

420

dataModel.put("items", new SimpleSequence(Arrays.asList("A", "B", "C")));

421

```

422

423

### Custom Model Implementation

424

425

For complex scenarios, implement model interfaces directly:

426

427

```java

428

public class ProductModel implements TemplateHashModel {

429

private Product product;

430

431

public ProductModel(Product product) {

432

this.product = product;

433

}

434

435

public TemplateModel get(String key) throws TemplateModelException {

436

if ("name".equals(key)) return new SimpleScalar(product.getName());

437

if ("price".equals(key)) return new SimpleNumber(product.getPrice());

438

if ("inStock".equals(key)) return product.isInStock() ?

439

TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;

440

return null;

441

}

442

443

public boolean isEmpty() {

444

return false;

445

}

446

}

447

```