JAXB Binding Compiler (XJC) that generates Java classes from XML Schema definitions with both command-line and programmatic APIs
—
The JAXB XJC code generation system provides comprehensive control over how Java classes are generated from XML schemas, with customizable field rendering, type mapping, and code structure.
The outline system provides a structured view of the generated code, allowing plugins and customization to modify the generation process.
/**
* Root interface providing access to all generated code elements
*/
public interface Outline {
/**
* Get the underlying schema model
* @return Model containing parsed schema information
*/
Model getModel();
/**
* Get the CodeModel containing generated classes
* @return JCodeModel with all generated code
*/
JCodeModel getCodeModel();
/**
* Get all generated class outlines
* @return Collection of ClassOutline objects
*/
Collection<? extends ClassOutline> getClasses();
/**
* Get specific class outline for a model class
* @param clazz CClassInfo from the model
* @return ClassOutline for the specified class, or null if not found
*/
ClassOutline getClazz(CClassInfo clazz);
/**
* Get field outline for a specific property
* @param fu CPropertyInfo from the model
* @return FieldOutline for the specified property, or null if not found
*/
FieldOutline getField(CPropertyInfo fu);
/**
* Get package context for a specific package
* @param _Package JPackage to get context for
* @return PackageOutline containing package-level information
*/
PackageOutline getPackageContext(JPackage _Package);
}Per-class code generation information and customization points.
/**
* Represents generated code for a single XML Schema complex type
*/
public abstract class ClassOutline {
/**
* Target class information from the model
*/
public final CClassInfo target;
/**
* Generated class reference in the code model
*/
public final JDefinedClass ref;
/**
* Get parent outline
* @return Parent Outline object
*/
public abstract Outline parent();
/**
* Get all declared fields for this class
* @return Array of FieldOutline objects
*/
public abstract FieldOutline[] getDeclaredFields();
/**
* Get superclass outline if this class extends another generated class
* @return ClassOutline of superclass, or null if no generated superclass
*/
public abstract ClassOutline getSuperClass();
}Fine-grained control over individual field generation and access patterns.
/**
* Represents generated code for a single XML Schema element or attribute
*/
public abstract class FieldOutline {
/**
* Get the property information from the model
* @return CPropertyInfo containing schema binding information
*/
public abstract CPropertyInfo getPropertyInfo();
/**
* Get the parent class outline
* @return ClassOutline containing this field
*/
public abstract ClassOutline parent();
/**
* Get the raw Java type for this field
* @return JType representing the Java type
*/
public abstract JType getRawType();
/**
* Generate getter method expression
* @return JExpression for accessing the field value
*/
public abstract JExpression createGetter();
/**
* Generate setter method expression
* @param value JExpression representing the value to set
* @return JExpression for setting the field value
*/
public abstract JExpression createSetter(JExpression value);
}Customizable field rendering strategies for different collection and property types.
/**
* Factory for creating field renderers based on property characteristics
*/
public interface FieldRendererFactory {
/**
* Get default field renderer for single-valued properties
* @return FieldRenderer for default single value fields
*/
FieldRenderer getDefault();
/**
* Get array field renderer for array properties
* @return FieldRenderer for array fields
*/
FieldRenderer getArray();
/**
* Get list field renderer for collection properties
* @param coreList JClass representing the list implementation type
* @return FieldRenderer for list fields
*/
FieldRenderer getList(JClass coreList);
/**
* Get single field renderer for required single-valued properties
* @return FieldRenderer for required single value fields
*/
FieldRenderer getSingle();
/**
* Get constant field renderer with fallback for read-only properties
* @param fallback FieldRenderer to use as fallback for non-constant cases
* @return FieldRenderer for constant fields
*/
FieldRenderer getConst(FieldRenderer fallback);
}
/**
* Strategy interface for rendering individual fields with different access patterns
*/
public interface FieldRenderer {
// Implementation details vary by renderer type
// Generates appropriate getter/setter methods and field declarations
}Custom Field Renderer Example:
import com.sun.tools.xjc.generator.bean.field.*;
import com.sun.tools.xjc.outline.*;
import com.sun.codemodel.*;
public class FluentFieldRenderer implements FieldRenderer {
private final FieldRenderer core;
public FluentFieldRenderer(FieldRenderer core) {
this.core = core;
}
// Generate fluent setter methods that return 'this'
public JMethod generateSetter(ClassOutline classOutline, FieldOutline fieldOutline) {
JMethod setter = core.generateSetter(classOutline, fieldOutline);
// Modify return type to be fluent
setter.type(classOutline.ref);
setter.body()._return(JExpr._this());
return setter;
}
}Main bean generator implementing the generation process from model to code.
/**
* Primary bean generator that implements the Outline interface
*/
public class BeanGenerator implements Outline {
/**
* Generate Java beans from the provided model
* @param model Schema model containing all type information
* @param errorReceiver Error handler for generation issues
* @return Outline containing all generated code
*/
public static Outline generate(Model model, ErrorReceiver errorReceiver);
// Outline interface implementation
public Model getModel();
public JCodeModel getCodeModel();
public Collection<? extends ClassOutline> getClasses();
public ClassOutline getClazz(CClassInfo clazz);
public FieldOutline getField(CPropertyInfo fu);
public PackageOutline getPackageContext(JPackage _Package);
}
/**
* Interface for generating ObjectFactory classes
*/
public interface ObjectFactoryGenerator {
/**
* Generate factory methods for the specified element
* @param cc ClassOutline for the containing class
* @param element CElementInfo for the element
* @param eo ElementOutline containing element generation info
*/
void populate(ClassOutline cc, CElementInfo element, ElementOutline eo);
}Package-level code generation and organization.
/**
* Package-level information and generated content
*/
public interface PackageOutline {
/**
* Get the JPackage representing this package
* @return JPackage in the code model
*/
JPackage _package();
/**
* Get ObjectFactory class for this package
* @return JDefinedClass representing the ObjectFactory
*/
JDefinedClass objectFactory();
/**
* Get package-info class if generated
* @return JDefinedClass for package-info, or null if not generated
*/
JDefinedClass packageInfo();
}Advanced customization options and patterns for specialized generation needs.
Custom Code Writer:
import com.sun.codemodel.*;
import com.sun.codemodel.writer.FileCodeWriter;
import java.io.File;
import java.io.IOException;
public class CustomCodeWriter extends FileCodeWriter {
public CustomCodeWriter(File target) throws IOException {
super(target);
}
@Override
public Writer openSource(JPackage pkg, String fileName) throws IOException {
// Add custom header to all generated files
Writer writer = super.openSource(pkg, fileName);
writer.write("// This file was generated by Custom XJC Plugin\n");
writer.write("// Generation time: " + new Date() + "\n\n");
return writer;
}
}Type Mapping Customization:
import com.sun.tools.xjc.model.Model;
import com.sun.tools.xjc.model.CClassInfo;
import com.sun.codemodel.JType;
public class CustomTypeMapping {
public static void customizeModel(Model model) {
// Replace default date handling
for (CClassInfo classInfo : model.beans().values()) {
for (CPropertyInfo property : classInfo.getProperties()) {
if (property.getName(false).toLowerCase().contains("date")) {
// Customize date property generation
customizeDateProperty(property);
}
}
}
}
private static void customizeDateProperty(CPropertyInfo property) {
// Custom date handling logic
// Could change type mapping, add custom adapters, etc.
}
}Basic Code Generation:
import com.sun.tools.xjc.api.*;
import com.sun.tools.xjc.generator.bean.BeanGenerator;
import com.sun.tools.xjc.model.Model;
import com.sun.tools.xjc.outline.Outline;
import com.sun.codemodel.*;
// Parse schema and create model
SchemaCompiler compiler = XJC.createSchemaCompiler();
compiler.parseSchema(schemaSource);
S2JJAXBModel jaxbModel = compiler.bind();
// Generate outline
Model model = ((ModelImpl) jaxbModel).getModel();
Outline outline = BeanGenerator.generate(model, errorReceiver);
// Access generated classes
for (ClassOutline classOutline : outline.getClasses()) {
JDefinedClass generatedClass = classOutline.ref;
System.out.println("Generated class: " + generatedClass.fullName());
// Examine fields
for (FieldOutline fieldOutline : classOutline.getDeclaredFields()) {
String fieldName = fieldOutline.getPropertyInfo().getName(false);
JType fieldType = fieldOutline.getRawType();
System.out.printf(" Field: %s %s%n", fieldType.name(), fieldName);
}
}Custom Field Rendering:
import com.sun.tools.xjc.Options;
import com.sun.tools.xjc.generator.bean.field.*;
// Create custom field renderer factory
FieldRendererFactory customFactory = new FieldRendererFactory() {
@Override
public FieldRenderer getDefault() {
return new FluentFieldRenderer(new DefaultFieldRenderer());
}
@Override
public FieldRenderer getList(JClass coreList) {
return new ImmutableListFieldRenderer(coreList);
}
// ... other renderer methods
};
// Apply custom factory to options
Options options = new Options();
options.setFieldRendererFactory(customFactory, null);Post-Generation Customization:
public class PostGenerationCustomizer {
public static void customize(Outline outline) {
// Add custom methods to all generated classes
for (ClassOutline classOutline : outline.getClasses()) {
addValidationMethod(classOutline);
addBuilderPattern(classOutline);
addToStringMethod(classOutline);
}
}
private static void addValidationMethod(ClassOutline classOutline) {
JDefinedClass clazz = classOutline.ref;
JCodeModel codeModel = clazz.owner();
// Add validate() method
JMethod validate = clazz.method(JMod.PUBLIC, codeModel.VOID, "validate");
validate.annotate(Override.class);
JBlock body = validate.body();
// Add validation logic for each field
for (FieldOutline fieldOutline : classOutline.getDeclaredFields()) {
CPropertyInfo property = fieldOutline.getPropertyInfo();
if (property.isRequired()) {
JExpression getter = fieldOutline.createGetter();
JConditional nullCheck = body._if(getter.eq(JExpr._null()));
nullCheck._then()._throw(JExpr._new(codeModel.ref(IllegalStateException.class))
.arg("Required field " + property.getName(false) + " is null"));
}
}
}
}This code generation system provides complete control over how XML schemas are transformed into Java code, enabling developers to create highly customized and optimized JAXB bindings for their specific use cases.
Install with Tessl CLI
npx tessl i tessl/maven-org-glassfish-jaxb--jaxb-xjc