Dynamic MOXy - Bootstrapping from XML Schema

Overview

Support for bootstrapping a DynamicJAXBContext from an XML Schema file (XSD) will be implemented in multiple phases. For each phase, test schemas will be created that would result in the following annotations being generated by XJC. A DynamicJAXBContext will then be created from each schema, and an example object will be marshalled. The resulting document will be inspected to ensure that it was marshalled properly, according to the annotations being tested.

Generating a DynamicJAXBContext with XJC

A DynamicJAXBContext is created from an XSD in the following way:

The schema is parsed using com.sun.tools.xjc.api.SchemaCompiler, resulting in a com.sun.codemodel.JCodeModel being generated.

JCodeModel contains XJC representations (com.sun.codemodel.JDefinedClass) of the classes to be generated. We iterate over the collection of JDefinedClasses to create EclipseLink representations of the same classes (org.eclipse.persistence.jaxb.javamodel.xjc.*)

This collection of EclipseLink javamodel classes is then passed to org.eclipse.persistence.jaxb.compiler.Generator, which generates a standard EclipseLink project.

A Dynamic Project is then created from the standard project via DynamicTypeBuilder.loadDynamicProject().

An org.eclipse.persistence.oxm.XMLContext is then created from the Dynamic Project, and a DynamicJAXBContext is returned backed by this XMLContext.

The element declaration for individuo will result in an @XmlElementDecl annotation on the generated ObjectFactory class.

As a result of the @XmlElementDecl annotation, ObjectFactory will also be annotated with an @XmlRegistry.

Design

When constructing a DynamicJAXBContext from XML Schema, we can use APIs from the Java XJC compiler to parse a schema and create Java class definitions (XJC's JCodeModel) in memory, then pass these class definitions to an EclipseLink Generator (org.eclipse.persistence.jaxb.compiler.Generator) to generate an EclipseLink project. After we have created this project, we can use the DynamicTypeBuilder to create a dynamic project, generating Java classes in memory along the way.

First, we use XJC API to parse an XSD and generate a JCodeModel. Note that this code stops short of actually generating .java files, it only generates an in-memory representation of the Java files that would normally be created.

We can then wrap these XJC classes in our own implentations of EclipseLink's JAXB JavaModel classes. This will allow us to use the Generator to create an EclipseLink project and mappings. The JavaModel interfaces define "wrappers" for the various Java language constructs that make up the domain model (e.g. classes, methods, constructors, annotations, packages, etc). For example:

At this point, we can instantiate a Generator and obtain a "dry" EclipseLink project, which we can then turn into a dynamic project with generated in-memory classes. Finally, we create and store an XMLContext and a DynamicHelper:

// Use the JavaModel to setup a Generator to generate an EclipseLink project
XJCJavaModelImpl javaModel = new XJCJavaModelImpl(Thread.currentThread().getContextClassLoader(), jCodeModel);
XJCJavaModelInputImpl javaModelInput = new XJCJavaModelInputImpl(jotClasses, javaModel);
Generator g = new Generator(javaModelInput);
Project p = g.generateProject();// Make a Dynamic Project from this project, because these classes do not exist on the classpath
DynamicClassLoader dynamicClassLoader;if(classLoader instanceof DynamicClassLoader){
dynamicClassLoader = classLoader;}else{
dynamicClassLoader = new DynamicClassLoader(classLoader);}
Project dp = DynamicTypeBuilder.loadDynamicProject(p, null, dynamicClassLoader);this.xmlContext = new XMLContext(dp);this.dynamicHelper = new DynamicHelper(xmlContext.getSession(0));