or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

build-system.mdconfiguration.mddev-mode.mdindex.mdpackaging.mdutilities.md

build-system.mddocs/

0

# Build System

1

2

The Quarkus build system is built around a producer-consumer model where build steps declare their inputs and outputs through build items. This enables dependency resolution, parallel execution, and extensibility for the deployment-time augmentation process.

3

4

## Core Imports

5

6

```java

7

// Build step annotations

8

import io.quarkus.deployment.annotations.BuildStep;

9

import io.quarkus.deployment.annotations.BuildProducer;

10

import io.quarkus.deployment.annotations.Record;

11

import io.quarkus.deployment.annotations.ExecutionTime;

12

import io.quarkus.deployment.annotations.Consume;

13

import io.quarkus.deployment.annotations.Produce;

14

import io.quarkus.deployment.annotations.BuildSteps;

15

import io.quarkus.deployment.annotations.Overridable;

16

import io.quarkus.deployment.annotations.ProduceWeak;

17

import io.quarkus.deployment.annotations.Weak;

18

19

// Build items base classes

20

import io.quarkus.deployment.builditem.BuildItem;

21

import io.quarkus.deployment.builditem.SimpleBuildItem;

22

import io.quarkus.deployment.builditem.MultiBuildItem;

23

24

// Bytecode recording

25

import io.quarkus.deployment.recording.RecorderContext;

26

import io.quarkus.deployment.recording.BytecodeRecorderImpl;

27

```

28

29

## Build Step Annotations

30

31

### @BuildStep

32

33

Marks a method as a build step that participates in the build chain.

34

35

```java { .api }

36

@Target(ElementType.METHOD)

37

@Retention(RetentionPolicy.RUNTIME)

38

@interface BuildStep {

39

/**

40

* Conditional execution suppliers - step runs only if ALL return true

41

*/

42

Class<? extends BooleanSupplier>[] onlyIf() default {};

43

44

/**

45

* Negative conditional execution suppliers - step runs only if ALL return false

46

*/

47

Class<? extends BooleanSupplier>[] onlyIfNot() default {};

48

}

49

```

50

51

**Usage Examples:**

52

53

```java

54

// Simple build step

55

@BuildStep

56

FeatureBuildItem registerFeature() {

57

return new FeatureBuildItem(Feature.REST);

58

}

59

60

// Conditional build step

61

@BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)

62

void processNativeImage(BuildProducer<NativeImageResourceBuildItem> resources) {

63

resources.produce(new NativeImageResourceBuildItem("META-INF/services/*"));

64

}

65

66

// Build step with multiple conditions

67

@BuildStep(

68

onlyIf = { DevelopmentMode.class, DevServicesEnabled.class },

69

onlyIfNot = { TestProfile.class }

70

)

71

void setupDevServices(BuildProducer<DevServicesBuildItem> devServices) {

72

// Development services setup

73

}

74

```

75

76

### @BuildProducer

77

78

Interface for producing build items during build step execution.

79

80

```java { .api }

81

interface BuildProducer<T extends BuildItem> {

82

/**

83

* Produces a single build item

84

*/

85

void produce(T item);

86

87

/**

88

* Produces multiple build items

89

*/

90

void produce(Collection<T> items);

91

}

92

```

93

94

**Usage Examples:**

95

96

```java

97

@BuildStep

98

void registerReflection(BuildProducer<ReflectiveClassBuildItem> reflectiveClasses) {

99

reflectiveClasses.produce(ReflectiveClassBuildItem.builder(MyClass.class)

100

.constructors()

101

.methods()

102

.fields()

103

.build());

104

}

105

106

@BuildStep

107

void registerMultipleCapabilities(BuildProducer<CapabilityBuildItem> capabilities) {

108

List<CapabilityBuildItem> items = Arrays.asList(

109

new CapabilityBuildItem(Capability.REST),

110

new CapabilityBuildItem(Capability.SECURITY)

111

);

112

capabilities.produce(items);

113

}

114

```

115

116

### @Record

117

118

Marks build steps that generate bytecode for runtime execution.

119

120

```java { .api }

121

@Target(ElementType.METHOD)

122

@Retention(RetentionPolicy.RUNTIME)

123

@interface Record {

124

/**

125

* When the recorded bytecode should execute

126

*/

127

ExecutionTime value() default ExecutionTime.RUNTIME_INIT;

128

129

/**

130

* Whether bytecode production is optional

131

*/

132

boolean optional() default false;

133

134

/**

135

* Use identity comparison for recorder parameters

136

*/

137

boolean useIdentityComparisonForParameters() default false;

138

}

139

140

enum ExecutionTime {

141

/**

142

* Execute from static initializer (build time)

143

*/

144

STATIC_INIT,

145

146

/**

147

* Execute from main method (runtime initialization)

148

*/

149

RUNTIME_INIT

150

}

151

```

152

153

**Usage Examples:**

154

155

```java

156

@BuildStep

157

@Record(ExecutionTime.STATIC_INIT)

158

void configureStaticInit(MyRecorder recorder,

159

ConfigurationBuildItem config) {

160

recorder.setupStaticConfiguration(config.getProperties());

161

}

162

163

@BuildStep

164

@Record(ExecutionTime.RUNTIME_INIT)

165

void configureRuntime(MyRecorder recorder,

166

LaunchModeBuildItem launchMode,

167

ShutdownContextBuildItem shutdownContext) {

168

recorder.initialize(launchMode.getLaunchMode(), shutdownContext);

169

}

170

171

// Optional recording - may not execute if conditions aren't met

172

@BuildStep

173

@Record(value = ExecutionTime.RUNTIME_INIT, optional = true)

174

void conditionalSetup(MyRecorder recorder,

175

Optional<DatabaseBuildItem> database) {

176

if (database.isPresent()) {

177

recorder.configureDatabase(database.get());

178

}

179

}

180

```

181

182

### Build Step Dependencies

183

184

Control execution order and dependencies between build steps.

185

186

```java { .api }

187

@Target(ElementType.METHOD)

188

@Retention(RetentionPolicy.RUNTIME)

189

@interface Consume {

190

/**

191

* Build item type that must be produced before this step runs

192

*/

193

Class<? extends BuildItem> value();

194

}

195

196

@Target(ElementType.METHOD)

197

@Retention(RetentionPolicy.RUNTIME)

198

@interface Produce {

199

/**

200

* Build item type this step produces

201

*/

202

Class<? extends BuildItem> value();

203

}

204

205

@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE_USE})

206

@Retention(RetentionPolicy.RUNTIME)

207

@interface Weak {

208

// Marks weak dependencies that don't require execution order

209

}

210

211

@Target(ElementType.METHOD)

212

@Retention(RetentionPolicy.RUNTIME)

213

@interface ProduceWeak {

214

/**

215

* Weak build item type this step produces

216

*/

217

Class<? extends BuildItem> value();

218

}

219

```

220

221

**Usage Examples:**

222

223

```java

224

@BuildStep

225

@Consume(ApplicationIndexBuildItem.class)

226

void processAfterIndexing(ApplicationIndexBuildItem index,

227

BuildProducer<GeneratedClassBuildItem> generated) {

228

// This runs after application indexing is complete

229

}

230

231

@BuildStep

232

@Produce(CustomBuildItem.class)

233

CustomBuildItem createCustomItem() {

234

return new CustomBuildItem();

235

}

236

237

@BuildStep

238

@ProduceWeak(OptionalFeatureBuildItem.class)

239

OptionalFeatureBuildItem maybeProvideFeature() {

240

// Weak production - others can override this

241

return new OptionalFeatureBuildItem();

242

}

243

244

@BuildStep

245

void consumeWeakItem(@Weak OptionalFeatureBuildItem weak) {

246

// Weak consumption - step runs regardless of weak item presence

247

}

248

```

249

250

### Class-Level Annotations

251

252

```java { .api }

253

@Target(ElementType.TYPE)

254

@Retention(RetentionPolicy.RUNTIME)

255

@interface BuildSteps {

256

/**

257

* Class-wide conditional execution suppliers

258

*/

259

Class<? extends BooleanSupplier>[] onlyIf() default {};

260

261

/**

262

* Class-wide negative conditional execution suppliers

263

*/

264

Class<? extends BooleanSupplier>[] onlyIfNot() default {};

265

}

266

267

@Target(ElementType.METHOD)

268

@Retention(RetentionPolicy.RUNTIME)

269

@interface Overridable {

270

// Marks build items as overridable by other extensions

271

}

272

```

273

274

**Usage Examples:**

275

276

```java

277

@BuildSteps(onlyIf = DevelopmentMode.class)

278

public class DevModeProcessor {

279

280

@BuildStep

281

void setupHotReload() {

282

// Only runs in development mode

283

}

284

285

@BuildStep

286

void setupDevConsole() {

287

// Also only runs in development mode

288

}

289

}

290

291

@BuildStep

292

@Overridable

293

SecurityProviderBuildItem defaultSecurity() {

294

return new SecurityProviderBuildItem("default");

295

}

296

```

297

298

## Build Items

299

300

### Base Classes

301

302

```java { .api }

303

/**

304

* Base class for all build items

305

*/

306

abstract class BuildItem {}

307

308

/**

309

* Build item with single instance per build

310

*/

311

abstract class SimpleBuildItem extends BuildItem {}

312

313

/**

314

* Build item allowing multiple instances per build

315

*/

316

abstract class MultiBuildItem extends BuildItem {}

317

```

318

319

### Creating Custom Build Items

320

321

```java

322

// Simple build item (single instance)

323

public final class DatabaseConfigBuildItem extends SimpleBuildItem {

324

private final String url;

325

private final String driver;

326

327

public DatabaseConfigBuildItem(String url, String driver) {

328

this.url = url;

329

this.driver = driver;

330

}

331

332

public String getUrl() { return url; }

333

public String getDriver() { return driver; }

334

}

335

336

// Multi build item (multiple instances allowed)

337

public final class EntityBuildItem extends MultiBuildItem {

338

private final String className;

339

private final String tableName;

340

341

public EntityBuildItem(String className, String tableName) {

342

this.className = className;

343

this.tableName = tableName;

344

}

345

346

public String getClassName() { return className; }

347

public String getTableName() { return tableName; }

348

}

349

```

350

351

## Bytecode Recording

352

353

### RecorderContext

354

355

Provides context for bytecode recording operations.

356

357

```java { .api }

358

class RecorderContext {

359

/**

360

* Creates a new class writer for generating classes

361

*/

362

ClassCreator getClassCreator(String className);

363

364

/**

365

* Registers an object loader for custom object handling

366

*/

367

void registerObjectLoader(ObjectLoader loader);

368

369

/**

370

* Creates a recorder proxy for the given class

371

*/

372

<T> T getRecorderProxy(Class<T> recorderClass);

373

374

/**

375

* Converts a class to a runtime proxy

376

*/

377

RuntimeValue<Class<?>> classProxy(String className);

378

379

/**

380

* Creates a runtime value wrapper

381

*/

382

<T> RuntimeValue<T> newInstance(String className);

383

}

384

```

385

386

### ObjectLoader Interface

387

388

Custom object loading during bytecode recording.

389

390

```java { .api }

391

interface ObjectLoader {

392

/**

393

* Loads an object into bytecode

394

*/

395

ResultHandle load(BytecodeCreator body, Object obj, boolean staticInit);

396

397

/**

398

* Checks if this loader can handle the given object

399

*/

400

boolean canHandleObject(Object obj, boolean staticInit);

401

}

402

```

403

404

**Usage Examples:**

405

406

```java

407

public class CustomObjectLoader implements ObjectLoader {

408

409

@Override

410

public boolean canHandleObject(Object obj, boolean staticInit) {

411

return obj instanceof MyCustomType;

412

}

413

414

@Override

415

public ResultHandle load(BytecodeCreator body, Object obj, boolean staticInit) {

416

MyCustomType custom = (MyCustomType) obj;

417

418

return body.newInstance(

419

MethodDescriptor.ofConstructor(MyCustomType.class, String.class),

420

body.load(custom.getValue())

421

);

422

}

423

}

424

425

// Register in recorder context

426

@BuildStep

427

@Record(ExecutionTime.RUNTIME_INIT)

428

void setupRecording(RecorderContext context, MyRecorder recorder) {

429

context.registerObjectLoader(new CustomObjectLoader());

430

recorder.initialize();

431

}

432

```

433

434

## Extension Development Patterns

435

436

### Basic Extension Structure

437

438

```java

439

public class MyExtensionProcessor {

440

441

@BuildStep

442

FeatureBuildItem registerFeature() {

443

return new FeatureBuildItem("my-extension");

444

}

445

446

@BuildStep

447

CapabilityBuildItem registerCapability() {

448

return new CapabilityBuildItem("com.example.my-capability");

449

}

450

451

@BuildStep

452

void processConfiguration(MyExtensionConfig config,

453

BuildProducer<MyConfigBuildItem> producer) {

454

producer.produce(new MyConfigBuildItem(config));

455

}

456

457

@BuildStep

458

@Record(ExecutionTime.RUNTIME_INIT)

459

void setupRuntime(MyRecorder recorder,

460

MyConfigBuildItem config,

461

ShutdownContextBuildItem shutdown) {

462

recorder.initialize(config.getProperties(), shutdown);

463

}

464

}

465

```

466

467

### Conditional Extension Activation

468

469

```java

470

public class ConditionalProcessor {

471

472

@BuildStep(onlyIf = DatabasePresent.class)

473

void setupDatabase(BuildProducer<DatabaseBuildItem> database) {

474

// Only runs if database dependency is present

475

}

476

477

@BuildStep(onlyIfNot = ProductionMode.class)

478

void setupDevMode(BuildProducer<DevServicesBuildItem> devServices) {

479

// Only runs when not in production mode

480

}

481

}

482

483

public class DatabasePresent implements BooleanSupplier {

484

@Override

485

public boolean getAsBoolean() {

486

try {

487

Class.forName("javax.sql.DataSource");

488

return true;

489

} catch (ClassNotFoundException e) {

490

return false;

491

}

492

}

493

}

494

```

495

496

### Build Chain Customization

497

498

```java

499

public class BuildChainCustomizer {

500

501

public static Consumer<BuildChainBuilder> customize() {

502

return builder -> {

503

builder.addBuildStep(MyProcessor.class);

504

builder.addFinal(MyFinalProcessor.class);

505

builder.addInitial(MyInitialProcessor.class);

506

};

507

}

508

}

509

510

// Usage in augmentor

511

QuarkusAugmentor augmentor = QuarkusAugmentor.builder()

512

.setRoot(root)

513

.addBuildChainCustomizer(BuildChainCustomizer.customize())

514

.build();

515

```