or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

build-integration.mdcli.mdcode-generation.mderror-handling.mdindex.mdplugin-system.mdprogrammatic-api.md

plugin-system.mddocs/

0

# Plugin System

1

2

The JAXB XJC plugin system provides an extensible architecture for customizing code generation, adding annotations, and implementing domain-specific features through a well-defined plugin interface.

3

4

## Capabilities

5

6

### Base Plugin Class

7

8

Abstract base class that all XJC plugins must extend to participate in the code generation process.

9

10

```java { .api }

11

/**

12

* Abstract base class for XJC plugins that customize code generation

13

*/

14

public abstract class Plugin {

15

/**

16

* Get the command-line option name for this plugin

17

* @return Option name without leading dash (e.g., "fluent-api")

18

*/

19

public abstract String getOptionName();

20

21

/**

22

* Get usage description for help output

23

* @return Multi-line usage description

24

*/

25

public abstract String getUsage();

26

27

/**

28

* Main plugin execution method called during code generation

29

* @param outline Generated code outline containing all classes and fields

30

* @param opt Compilation options and configuration

31

* @param errorHandler Error handler for reporting issues

32

* @return true if plugin execution was successful

33

* @throws SAXException if plugin execution fails

34

*/

35

public abstract boolean run(Outline outline, Options opt, ErrorHandler errorHandler) throws SAXException;

36

37

/**

38

* Parse plugin-specific command line arguments

39

* @param opt Options object for storing parsed values

40

* @param args Full command line arguments array

41

* @param i Current position in args array

42

* @return Number of arguments consumed (0 if argument not recognized)

43

* @throws BadCommandLineException if argument is invalid

44

* @throws IOException if I/O error occurs during parsing

45

*/

46

public int parseArgument(Options opt, String[] args, int i) throws BadCommandLineException, IOException;

47

48

/**

49

* Get list of XML namespace URIs that this plugin handles in binding customizations

50

* @return List of namespace URIs, empty list if none

51

*/

52

public List<String> getCustomizationURIs();

53

54

/**

55

* Called when plugin is activated via command line

56

* @param opts Options object for configuration

57

* @throws BadCommandLineException if plugin activation fails

58

*/

59

public void onActivated(Options opts) throws BadCommandLineException;

60

61

/**

62

* Post-process the schema model before code generation

63

* @param model Schema model containing parsed information

64

* @param errorHandler Error handler for reporting issues

65

*/

66

public void postProcessModel(Model model, ErrorHandler errorHandler);

67

}

68

```

69

70

**Plugin Development Example:**

71

72

```java

73

import com.sun.tools.xjc.Plugin;

74

import com.sun.tools.xjc.outline.Outline;

75

import com.sun.tools.xjc.outline.ClassOutline;

76

import com.sun.tools.xjc.Options;

77

import com.sun.codemodel.*;

78

import org.xml.sax.ErrorHandler;

79

import org.xml.sax.SAXException;

80

81

public class ToStringPlugin extends Plugin {

82

83

@Override

84

public String getOptionName() {

85

return "Xtostring";

86

}

87

88

@Override

89

public String getUsage() {

90

return " -Xtostring : Generate toString() methods for all classes";

91

}

92

93

@Override

94

public boolean run(Outline outline, Options opt, ErrorHandler errorHandler) throws SAXException {

95

// Iterate through all generated classes

96

for (ClassOutline classOutline : outline.getClasses()) {

97

generateToString(classOutline);

98

}

99

return true;

100

}

101

102

private void generateToString(ClassOutline classOutline) {

103

JDefinedClass implClass = classOutline.ref;

104

105

// Generate toString method

106

JMethod toString = implClass.method(JMod.PUBLIC, String.class, "toString");

107

toString.annotate(Override.class);

108

109

JBlock body = toString.body();

110

JVar sb = body.decl(outline.getCodeModel().ref(StringBuilder.class), "sb",

111

JExpr._new(outline.getCodeModel().ref(StringBuilder.class)));

112

113

// Add class name

114

sb.invoke("append").arg(implClass.name() + "{");

115

116

// Add field values

117

boolean first = true;

118

for (FieldOutline field : classOutline.getDeclaredFields()) {

119

if (!first) {

120

sb.invoke("append").arg(", ");

121

}

122

sb.invoke("append").arg(field.getPropertyInfo().getName(false) + "=");

123

sb.invoke("append").arg(JExpr.refthis(field.getPropertyInfo().getName(false)));

124

first = false;

125

}

126

127

sb.invoke("append").arg("}");

128

body._return(sb.invoke("toString"));

129

}

130

}

131

```

132

133

### Built-in Plugins

134

135

XJC includes several built-in plugins that demonstrate common customization patterns.

136

137

```java { .api }

138

/**

139

* Built-in plugins provided by XJC

140

*/

141

142

// Accessor plugin for generating additional getter/setter methods

143

public class AccessorsPlugin extends Plugin {

144

public String getOptionName() { return "Xaccessors"; }

145

// Generates additional accessor methods

146

}

147

148

// @Generated annotation plugin

149

public class GeneratedPlugin extends Plugin {

150

public String getOptionName() { return "Xgenerated"; }

151

// Adds @Generated annotations to all generated classes

152

}

153

154

// Code injection plugin for custom code insertion

155

public class CodeInjectorPlugin extends Plugin {

156

public String getOptionName() { return "Xinject-code"; }

157

// Injects custom code from external sources

158

}

159

160

// Episode file generation plugin

161

public class EpisodePlugin extends Plugin {

162

public String getOptionName() { return "Xepisode"; }

163

// Generates episode files for modular compilation

164

}

165

166

// Source location tracking plugin

167

public class SourceLocationPlugin extends Plugin {

168

public String getOptionName() { return "Xlocator"; }

169

// Adds source location tracking to generated classes

170

}

171

172

// Synchronized method generation plugin

173

public class SynchronizedPlugin extends Plugin {

174

public String getOptionName() { return "Xsync-methods"; }

175

// Makes generated methods synchronized

176

}

177

```

178

179

### Plugin Registration and Discovery

180

181

Plugins are discovered and loaded using Java's ServiceLoader mechanism.

182

183

**Plugin Registration (META-INF/services/com.sun.tools.xjc.Plugin):**

184

```text

185

com.example.plugins.ToStringPlugin

186

com.example.plugins.BuilderPlugin

187

com.example.plugins.ValidationPlugin

188

```

189

190

**Module Declaration:**

191

```java

192

module my.xjc.plugins {

193

requires transitive org.glassfish.jaxb.xjc;

194

195

provides com.sun.tools.xjc.Plugin with

196

com.example.plugins.ToStringPlugin,

197

com.example.plugins.BuilderPlugin,

198

com.example.plugins.ValidationPlugin;

199

}

200

```

201

202

### Plugin Configuration and Arguments

203

204

Plugins can accept command-line arguments for configuration.

205

206

```java { .api }

207

/**

208

* Example plugin with configuration options

209

*/

210

public class ConfigurablePlugin extends Plugin {

211

private String prefix = "generated";

212

private boolean includeFields = true;

213

private Set<String> excludedClasses = new HashSet<>();

214

215

@Override

216

public int parseArgument(Options opt, String[] args, int i) throws BadCommandLineException {

217

String arg = args[i];

218

219

if (arg.equals("-Xplugin-prefix")) {

220

if (i + 1 < args.length) {

221

prefix = args[i + 1];

222

return 2; // Consumed current argument and next

223

} else {

224

throw new BadCommandLineException("Missing value for -Xplugin-prefix");

225

}

226

}

227

228

if (arg.equals("-Xplugin-no-fields")) {

229

includeFields = false;

230

return 1; // Consumed current argument

231

}

232

233

if (arg.equals("-Xplugin-exclude")) {

234

if (i + 1 < args.length) {

235

excludedClasses.add(args[i + 1]);

236

return 2;

237

} else {

238

throw new BadCommandLineException("Missing class name for -Xplugin-exclude");

239

}

240

}

241

242

return 0; // Argument not recognized

243

}

244

245

@Override

246

public void onActivated(Options opts) throws BadCommandLineException {

247

// Validate configuration after all arguments are parsed

248

if (prefix.isEmpty()) {

249

throw new BadCommandLineException("Plugin prefix cannot be empty");

250

}

251

}

252

}

253

```

254

255

### Advanced Plugin Patterns

256

257

**Model Post-Processing:**

258

```java

259

@Override

260

public void postProcessModel(Model model, ErrorHandler errorHandler) {

261

// Modify model before code generation

262

for (CClassInfo classInfo : model.beans().values()) {

263

// Add custom properties or modify existing ones

264

if (classInfo.getTypeName().getLocalPart().endsWith("Type")) {

265

// Rename classes ending with "Type"

266

String newName = classInfo.getTypeName().getLocalPart().replace("Type", "");

267

// Implementation would modify the class info

268

}

269

}

270

}

271

```

272

273

**Customization Processing:**

274

```java

275

@Override

276

public List<String> getCustomizationURIs() {

277

return Arrays.asList(

278

"http://example.com/xjc/builder",

279

"http://example.com/xjc/validation"

280

);

281

}

282

283

@Override

284

public boolean run(Outline outline, Options opt, ErrorHandler errorHandler) throws SAXException {

285

for (ClassOutline classOutline : outline.getClasses()) {

286

// Look for binding customizations

287

CPluginCustomization customization = classOutline.target.getCustomizations()

288

.find("http://example.com/xjc/builder", "builder");

289

290

if (customization != null) {

291

// Process the customization

292

generateBuilderPattern(classOutline, customization);

293

customization.markAsAcknowledged();

294

}

295

}

296

return true;

297

}

298

```

299

300

**Field-Level Customization:**

301

```java

302

@Override

303

public boolean run(Outline outline, Options opt, ErrorHandler errorHandler) throws SAXException {

304

for (ClassOutline classOutline : outline.getClasses()) {

305

for (FieldOutline fieldOutline : classOutline.getDeclaredFields()) {

306

CPropertyInfo property = fieldOutline.getPropertyInfo();

307

308

// Check for field-level customizations

309

if (property.getName(false).startsWith("id")) {

310

// Generate special handling for ID fields

311

generateIdFieldMethods(classOutline, fieldOutline);

312

}

313

314

// Modify field annotations

315

JFieldVar field = getFieldVar(fieldOutline);

316

if (field != null) {

317

field.annotate(MyCustomAnnotation.class);

318

}

319

}

320

}

321

return true;

322

}

323

```

324

325

### Plugin Usage Examples

326

327

**Command Line Usage:**

328

```bash

329

# Use built-in plugin

330

xjc -Xgenerated schema.xsd

331

332

# Use custom plugin with options

333

xjc -Xtostring schema.xsd

334

335

# Multiple plugins

336

xjc -Xgenerated -Xtostring -Xlocator schema.xsd

337

338

# Plugin with configuration

339

xjc -Xbuilder -Xbuilder-prefix=with schema.xsd

340

```

341

342

**Programmatic Usage:**

343

```java

344

import com.sun.tools.xjc.api.*;

345

import com.sun.tools.xjc.Plugin;

346

347

// Load and configure plugins

348

SchemaCompiler compiler = XJC.createSchemaCompiler();

349

compiler.parseSchema(schemaSource);

350

351

S2JJAXBModel model = compiler.bind();

352

353

// Apply plugins during code generation

354

Plugin[] plugins = {

355

new ToStringPlugin(),

356

new BuilderPlugin()

357

};

358

359

JCodeModel codeModel = model.generateCode(plugins, errorListener);

360

```

361

362

### Plugin Development Best Practices

363

364

1. **Error Handling**: Always use the provided ErrorHandler for reporting issues

365

2. **Resource Management**: Clean up any resources in plugin lifecycle methods

366

3. **Thread Safety**: Ensure plugins are thread-safe for concurrent usage

367

4. **Validation**: Validate configuration in onActivated() method

368

5. **Documentation**: Provide clear usage description and examples

369

6. **Customization**: Support binding customizations for fine-grained control

370

7. **Testing**: Test with various schema patterns and edge cases

371

372

### Common Plugin Use Cases

373

374

- **Code Quality**: Add toString(), equals(), hashCode() methods

375

- **Design Patterns**: Generate Builder, Factory, or Visitor patterns

376

- **Validation**: Add Bean Validation annotations

377

- **Documentation**: Generate JavaDoc comments from schema annotations

378

- **Serialization**: Add custom serialization support

379

- **Framework Integration**: Add Spring, JPA, or other framework annotations

380

- **Code Style**: Enforce naming conventions or coding standards