or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli-interface.mdcollections-utilities.mdcore-runtime.mdindex.mdjson-processing.mdmeta-programming.mdscript-execution.mdsql-database.mdtemplate-processing.mdxml-processing.md

meta-programming.mddocs/

0

# Meta-Programming

1

2

Comprehensive meta-programming capabilities for runtime method and property manipulation, dynamic behavior modification, and advanced meta-object protocol features.

3

4

## Capabilities

5

6

### MetaClass System

7

8

Core meta-programming interface for runtime method dispatch and property access.

9

10

```groovy { .api }

11

/**

12

* Core meta-class interface for runtime method dispatch and property access

13

*/

14

interface MetaClass {

15

/** Invoke method on object with given arguments */

16

Object invokeMethod(Object object, String methodName, Object[] arguments)

17

18

/** Invoke method on class (static method) */

19

Object invokeStaticMethod(Object object, String methodName, Object[] arguments)

20

21

/** Invoke constructor with arguments */

22

Object invokeConstructor(Object[] arguments)

23

24

/** Get property value from object */

25

Object getProperty(Object object, String property)

26

27

/** Set property value on object */

28

void setProperty(Object object, String property, Object newValue)

29

30

/** Get attribute (field) value */

31

Object getAttribute(Object object, String attribute)

32

33

/** Set attribute (field) value */

34

void setAttribute(Object object, String attribute, Object newValue)

35

36

/** Get list of all methods */

37

List<MetaMethod> getMethods()

38

39

/** Get list of methods by name */

40

List<MetaMethod> getMethods(String name)

41

42

/** Get list of all properties */

43

List<MetaProperty> getProperties()

44

45

/** Get specific property by name */

46

MetaProperty getMetaProperty(String name)

47

48

/** Check if method exists */

49

boolean hasMethod(String name, Object[] arguments)

50

51

/** Check if property exists */

52

boolean hasProperty(Object obj, String name)

53

54

/** Get the class this MetaClass represents */

55

Class getTheClass()

56

}

57

```

58

59

### MetaClass Implementation

60

61

Default implementation providing comprehensive meta-programming features.

62

63

```groovy { .api }

64

/**

65

* Default implementation of MetaClass

66

*/

67

class MetaClassImpl implements MetaClass, MutableMetaClass {

68

/** Create MetaClassImpl for given class */

69

MetaClassImpl(Class theClass)

70

71

/** Create with custom class registry */

72

MetaClassImpl(MetaClassRegistry registry, Class theClass)

73

74

/** Add new method to the metaclass */

75

void addNewMethod(String name, Closure closure)

76

77

/** Add new static method */

78

void addNewStaticMethod(String name, Closure closure)

79

80

/** Add new constructor */

81

void addNewConstructor(Closure closure)

82

83

/** Add new property getter */

84

void addNewProperty(String name, Closure getter)

85

86

/** Add new property with getter and setter */

87

void addNewProperty(String name, Closure getter, Closure setter)

88

89

/** Initialize the metaclass */

90

void initialize()

91

}

92

```

93

94

### ExpandoMetaClass

95

96

Dynamic meta-class that allows runtime addition of methods and properties.

97

98

```groovy { .api }

99

/**

100

* MetaClass that allows dynamic addition of methods and properties at runtime

101

*/

102

class ExpandoMetaClass extends MetaClassImpl {

103

/** Enable globally for all classes */

104

static void enableGlobally()

105

106

/** Disable globally */

107

static void disableGlobally()

108

109

/** Create ExpandoMetaClass for class */

110

ExpandoMetaClass(Class clazz)

111

112

/** Create with inheritance enabled */

113

ExpandoMetaClass(Class clazz, boolean register)

114

115

/** Define method on metaclass using closure */

116

void define(Closure definition)

117

118

/** Left shift operator for method addition */

119

ExpandoMetaClass leftShift(Closure closure)

120

121

/** Add method dynamically */

122

void addMethod(String name, Closure closure)

123

124

/** Add static method dynamically */

125

void addStaticMethod(String name, Closure closure)

126

127

/** Add constructor dynamically */

128

void addConstructor(Closure closure)

129

130

/** Add property dynamically */

131

void addProperty(String name, Object value)

132

}

133

```

134

135

**Usage Examples:**

136

137

```groovy

138

// Enable ExpandoMetaClass globally

139

ExpandoMetaClass.enableGlobally()

140

141

// Add method to existing class

142

String.metaClass.reverse = {

143

return delegate.reverse()

144

}

145

146

println "hello".reverse() // "olleh"

147

148

// Add method with parameters

149

String.metaClass.multiply = { times ->

150

return delegate * times

151

}

152

153

println "ha".multiply(3) // "hahaha"

154

155

// Add static method

156

Integer.metaClass.static.random = { max ->

157

return new Random().nextInt(max)

158

}

159

160

println Integer.random(100) // random number 0-99

161

162

// Add property

163

String.metaClass.getWordCount = {

164

return delegate.split(/\s+/).size()

165

}

166

167

println "hello world test".wordCount // 3

168

169

// Define multiple methods at once

170

String.metaClass.define {

171

palindrome = {

172

return delegate == delegate.reverse()

173

}

174

175

capitalize = {

176

return delegate.toLowerCase().split(' ').collect {

177

it.capitalize()

178

}.join(' ')

179

}

180

}

181

182

println "racecar".palindrome() // true

183

println "hello world".capitalize() // "Hello World"

184

185

// Add methods to specific instances

186

def person = new Person()

187

person.metaClass.greet = {

188

return "Hello, I'm ${delegate.name}"

189

}

190

println person.greet()

191

192

// Add constructor

193

Person.metaClass.constructor = { String name, int age ->

194

def instance = new Person()

195

instance.name = name

196

instance.age = age

197

return instance

198

}

199

200

def newPerson = new Person("Alice", 30)

201

```

202

203

### MetaMethod and MetaProperty

204

205

Representations of methods and properties in the meta-object system.

206

207

```groovy { .api }

208

/**

209

* Base class for meta-methods

210

*/

211

abstract class MetaMethod {

212

/** Get method name */

213

String getName()

214

215

/** Get return type */

216

Class getReturnType()

217

218

/** Get parameter types */

219

Class[] getParameterTypes()

220

221

/** Check if method is static */

222

boolean isStatic()

223

224

/** Check if method is public */

225

boolean isPublic()

226

227

/** Check if method is private */

228

boolean isPrivate()

229

230

/** Check if method is protected */

231

boolean isProtected()

232

233

/** Invoke the method */

234

Object invoke(Object object, Object[] arguments)

235

236

/** Get declaring class */

237

Class getDeclaringClass()

238

}

239

240

/**

241

* Represents a property in the meta-object system

242

*/

243

abstract class MetaProperty {

244

/** Get property name */

245

String getName()

246

247

/** Get property type */

248

Class getType()

249

250

/** Get property value from object */

251

Object getProperty(Object object)

252

253

/** Set property value on object */

254

void setProperty(Object object, Object newValue)

255

256

/** Get declaring class */

257

Class getDeclaringClass()

258

}

259

```

260

261

### MetaClassRegistry

262

263

Registry for managing MetaClass instances globally.

264

265

```groovy { .api }

266

/**

267

* Registry for MetaClass instances

268

*/

269

interface MetaClassRegistry {

270

/** Get MetaClass for given class */

271

MetaClass getMetaClass(Class theClass)

272

273

/** Set MetaClass for given class */

274

void setMetaClass(Class theClass, MetaClass theMetaClass)

275

276

/** Remove MetaClass for given class */

277

void removeMetaClass(Class theClass)

278

279

/** Get MetaClass for given object */

280

MetaClass getMetaClass(Object obj)

281

282

/** Add change event listener */

283

void addMetaClassRegistryChangeEventListener(MetaClassRegistryChangeEventListener listener)

284

285

/** Remove change event listener */

286

void removeMetaClassRegistryChangeEventListener(MetaClassRegistryChangeEventListener listener)

287

288

/** Get change listeners */

289

MetaClassRegistryChangeEventListener[] getMetaClassRegistryChangeEventListeners()

290

}

291

```

292

293

**Usage Examples:**

294

295

```groovy

296

// Get global registry

297

def registry = GroovySystem.metaClassRegistry

298

299

// Get metaclass for a class

300

def stringMetaClass = registry.getMetaClass(String)

301

println "String has ${stringMetaClass.methods.size()} methods"

302

303

// Set custom metaclass

304

def customMetaClass = new ExpandoMetaClass(String)

305

customMetaClass.shout = { delegate.toUpperCase() + "!!!" }

306

customMetaClass.initialize()

307

308

registry.setMetaClass(String, customMetaClass)

309

println "hello".shout() // "HELLO!!!"

310

311

// Listen for metaclass changes

312

registry.addMetaClassRegistryChangeEventListener { event ->

313

println "MetaClass changed for ${event.classToUpdate}"

314

}

315

```

316

317

### Categories

318

319

Temporary method additions using the Category pattern.

320

321

```groovy { .api }

322

/**

323

* Marks a class as a category for use with `use` blocks

324

*/

325

@interface Category {

326

Class value() default Object.class

327

}

328

329

/**

330

* Support for category-based method enhancement

331

*/

332

class GroovyCategorySupport {

333

/** Execute closure with category methods available */

334

static Object use(Class categoryClass, Closure closure)

335

336

/** Execute closure with multiple categories */

337

static Object use(List<Class> categoryClasses, Closure closure)

338

339

/** Execute closure with category instance */

340

static Object use(Object categoryInstance, Closure closure)

341

}

342

```

343

344

**Usage Examples:**

345

346

```groovy

347

import groovy.lang.Category

348

349

// Define a category class

350

@Category(String)

351

class StringUtils {

352

static String reverse() {

353

return this.reverse()

354

}

355

356

static boolean isPalindrome() {

357

def reversed = this.reverse()

358

return this.toLowerCase() == reversed.toLowerCase()

359

}

360

361

static String encrypt(String key) {

362

// Simple encryption example

363

return this.collect { char ->

364

(char as int) + (key as int)

365

}.collect {

366

it as char

367

}.join('')

368

}

369

}

370

371

// Use category methods temporarily

372

use(StringUtils) {

373

println "hello".reverse() // "olleh"

374

println "racecar".isPalindrome() // true

375

println "secret".encrypt("x") // encrypted string

376

}

377

378

// Outside use block, methods are not available

379

// "hello".reverse() // Would cause MissingMethodException

380

381

// Multiple categories

382

@Category(Number)

383

class NumberUtils {

384

static boolean isEven() {

385

return this % 2 == 0

386

}

387

388

static boolean isOdd() {

389

return this % 2 != 0

390

}

391

}

392

393

use([StringUtils, NumberUtils]) {

394

println "test".reverse() // String category method

395

println 42.isEven() // Number category method

396

}

397

```

398

399

### Method Missing and Property Missing

400

401

Handle missing method and property calls dynamically.

402

403

```groovy { .api }

404

/**

405

* Handle missing method calls (typically implemented in classes)

406

*/

407

Object methodMissing(String name, Object args) {

408

// Custom implementation for handling unknown method calls

409

}

410

411

/**

412

* Handle missing property access (typically implemented in classes)

413

*/

414

Object propertyMissing(String name) {

415

// Custom implementation for handling unknown property access

416

}

417

418

/**

419

* Handle missing property assignment (typically implemented in classes)

420

*/

421

Object propertyMissing(String name, Object value) {

422

// Custom implementation for handling unknown property assignment

423

}

424

```

425

426

**Usage Examples:**

427

428

```groovy

429

class DynamicBean {

430

private Map properties = [:]

431

432

// Handle missing property gets

433

def propertyMissing(String name) {

434

return properties[name]

435

}

436

437

// Handle missing property sets

438

def propertyMissing(String name, value) {

439

properties[name] = value

440

}

441

442

// Handle missing method calls

443

def methodMissing(String name, args) {

444

if (name.startsWith('get')) {

445

def propName = name[3..-1].toLowerCase()

446

return properties[propName]

447

} else if (name.startsWith('set')) {

448

def propName = name[3..-1].toLowerCase()

449

properties[propName] = args[0]

450

return this

451

} else {

452

throw new MissingMethodException(name, this.class, args)

453

}

454

}

455

}

456

457

def bean = new DynamicBean()

458

459

// Property syntax

460

bean.name = "Alice"

461

bean.age = 30

462

println bean.name // "Alice"

463

println bean.age // 30

464

465

// Method syntax

466

bean.setEmail("alice@example.com")

467

println bean.getEmail() // "alice@example.com"

468

469

// Method chaining

470

bean.setName("Bob").setAge(25)

471

println "${bean.name} is ${bean.age} years old"

472

```

473

474

### Interceptors

475

476

Intercept method calls for logging, security, or other cross-cutting concerns.

477

478

```groovy { .api }

479

/**

480

* Interface for method call interception

481

*/

482

interface Interceptor {

483

/** Called before method execution */

484

Object beforeInvoke(Object object, String methodName, Object[] arguments)

485

486

/** Called after method execution */

487

Object afterInvoke(Object object, String methodName, Object[] arguments, Object result)

488

489

/** Check if this interceptor applies to the method */

490

boolean doInvoke()

491

}

492

493

/**

494

* Tracing interceptor for debugging

495

*/

496

class TracingInterceptor implements Interceptor {

497

TracingInterceptor()

498

499

Object beforeInvoke(Object object, String methodName, Object[] arguments)

500

Object afterInvoke(Object object, String methodName, Object[] arguments, Object result)

501

boolean doInvoke()

502

}

503

```

504

505

**Usage Examples:**

506

507

```groovy

508

import groovy.lang.TracingInterceptor

509

510

// Add tracing to a class

511

def tracer = new TracingInterceptor()

512

def proxy = ProxyMetaClass.getInstance(String)

513

proxy.interceptor = tracer

514

proxy.use {

515

"hello".toUpperCase()

516

"world".reverse()

517

}

518

519

// Custom interceptor

520

class LoggingInterceptor implements Interceptor {

521

boolean doInvoke() { return true }

522

523

Object beforeInvoke(Object object, String methodName, Object[] arguments) {

524

println "Calling ${methodName} on ${object.class.simpleName} with args: ${arguments}"

525

return null

526

}

527

528

Object afterInvoke(Object object, String methodName, Object[] arguments, Object result) {

529

println "Method ${methodName} returned: ${result}"

530

return result

531

}

532

}

533

534

def logger = new LoggingInterceptor()

535

def proxyMeta = ProxyMetaClass.getInstance(List)

536

proxyMeta.interceptor = logger

537

proxyMeta.use {

538

def list = [1, 2, 3]

539

list.add(4)

540

list.size()

541

}

542

```