Skip to content

Latest commit

 

History

History
917 lines (684 loc) · 49 KB

README_de.md

File metadata and controls

917 lines (684 loc) · 49 KB

Issue Stats Issue Stats

jaxb2-rich-contract-plugin

A collection of JAXB / XJC plugins to generate advanced contract scenarios from XSD

Current Version: 2.1.0

This module is a collection of several plugins for the JAXB2 (Java API for XML binding) "XSD to Java Compiler" (XJC). These plugins are intended to add support for additional contracts to the classes generated by XJC. Currently, there are 7 plugin classes:

  1. fluent-builder: Generates a builder class for every class generated. Builders are implemented as inner classes, static methods are provided for a fluent builder pattern in the form MyClass.builder().withPropertyA(...).withPropertyB(...).build(). Builders also contain "copy..." methods to initialize the builder from another instance. Partial copying is also supported in the same way as in copy. This is particularly useful together with -Ximmutable (see above), but not usable together with -Xconstrained-properties (see below). fluent-builder offers a bunch of cool stuff usually not found in standard builder generators, such as generating builder from existing instances with optional partial copying, chained builders, <choice> expansion, etc.
  2. immutable: Will make generated classes immutable. Only makes sense together with "fluent-builder" plugin (see below), or any other builder or initialisation facility, like the well-known "value-constructor" plugin.
  3. group-contract: When using <attributeGroup> or <group> elements in an XSD, they are transformed as interface definitions, and any complexTypes using the groups will be generated as classes implementing this interface.
  4. clone: Will generate a simple deep "clone" method for the generated classes based on the heuristic that it only makes sense to traverse further down in the cloned object tree for members of types that are actually cloenable themselves.
  5. copy: Similar to "clone", will generate a simple deep "createCopy" method. The java API contract for the java.lang.Cloneable interface and the rules for overriding Object.clone() are defective by design. So the "copy" plugin uses its own API to realize the desired behavior. Also can generate a "partial createCopy" method, that takes a PropertyTree object which represents an include/exclude rule for nodes in the object tree to clone. Excluded nodes will not be cloned and left alone. Optionally, corresponding copy constructors can also be generated.
  6. constrained-properties: Will generate a complexTypes element members as bound and/or constrained properties as per the JavaBeans spec.
  7. meta: Generates a nested class representing a static metamodel of the generated classes. In the "enhanced" version, this contains information about the type and the XSD element from which the property was generated, in "simple" mode, there are only constants for the property names.

How to get it

Full documentation on GitHub

Get the source on GitHub

Download this project as a .zip file

Download this project as a tar.gz file

Get it with Maven (Now hosted on maven central):

    <groupId>net.codesup.util</groupId>
    <artifactId>jaxb2-rich-contract-plugin</artifactId>
    <version>2.1.0</version>

Version History

  • 1.0.0: Initial Version
  • 1.0.1: Added constrained-property plugin
  • 1.0.2: Added partial clone method generation
  • 1.0.3: Improvements in partial clone
  • 1.0.4: Added fluent builder and immutable plugins
  • 1.0.5: Added chainable fluent builder support
  • 1.1.0: New: -Ximmutable, Copy constructor support, fluent-builder copy from instance support, general fixes. Removed option to generate fluent builders without chained builder support.
  • 1.1.1: New: Type-safe selector support for partial clone/copy logic.
  • 1.1.2: Big fixes in selector logic
  • 1.1.3: Minor bug fixes in fluent-builder
  • 1.1.4: Fixed an error in fluent-builder where an initialization method wasn't properly overridden in derived builder classes, leading to the wrong builder type being returned when using chained sub-builders.
  • 1.1.5: Fixed error in Release Build process
  • 1.1.6: Fixed bug in group-contract plugin: Property names customised via binding info were generated incorrectly in the interface definitions.
  • 1.2.0: Major changes to the logic of partial cloning. The partial clone PropertyTree pattern replaces the previous PropertyPath, which had pretty unclear semantics. The new PropertyTree builders now just create a property tree, and on invocation of the "clone()" or "copyOf()" methods or the copy constructor, it is decided by an additional parameter whether the property tree should be considered an exclusion or an inclusion pattern. Additionally, the group-interface plugin has been modified to create interfaces also for the fluent builders, if the fluent-builder plugin is activated.
  • 1.2.3: Added "Copyable" interface and "createCopy" method which does the same thing as the "clone()" method, but doesn't suffer from the defective-by-design java.lang.Cloneable contract. It is planned to als add a "copyFrom" method to copy the state of another object into an existing object.
  • 1.3.1: Made fluent-builder plugin work in an "episode" (modular generation and compilation) context by also integrating compiled classes on the XJC classpath in the search for base and property classes.
  • 1.3.6: Also made group-interface work in an "episode" context, and fixed bug where empty interfaces were created if no implementation class for them could be found in the current module.
  • 1.4.0: group-interface is using its own episode file to maintain relationships to definitions in upstream modules. Command-line options for a specific plugin must now be given immediately after the plugin activation option ("-X..."). This way, name conflicts between plugin options are avoided. Static source files are generated via the JCodeModel.addResourceFile API, so a bug where the source files ended up in the root of the project tree should be fixed now. group-interface and fluent-builder now are working together more reliably.
  • 1.5.0: Added new Plugin "-Xmeta" to generate an inner class containing static meta information about the properties of a class. Internally, a common base class for plugins was extracted to help in command-line parsing and command-line documentation.
  • 1.5.1: Major updates to documentation, improvements to -Xmeta to expose static information about XSD definitions of properties.
  • 1.5.2:
    • Now hosted on Central
    • More updates to documentation
    • Customization of names of many generated source elements
    • Improved handling of CloneNotSupportedException in clone, copy, and fluent-builder plugins
  • 1.5.3:
    • Added maven "site" hosted on github pages
    • Improvements to javadoc comment generation
    • Improvements to documentation
  • 1.5.4:
    • Updates to generated documentation
    • changed groupId to net.codesup.util
  • 1.5.5:
    • immutable plugin: Added command line option to specify access level of default constructor
  • 1.5.6:
    • Added instance "newCopyBuilder" method generation
  • 1.5.7:
    • Fixed bug where partial copying in a builder didn't work
  • 1.5.8:
    • Bugfix: When generating builder interface, not all superinterfaces were declared in the "extends" clause.
    • Added command-line option to configure whether methods that could cause type clashes should be ommitted.
    • Added command-line option to configure suffix for instance fields of a builder holding sub-builders
  • 1.5.9:
    • fluent-builder: Added methods to initialize collection properties with an "java.util.Iterable" instance instead of collection.
    • fluent-builder: Made "add..." and "with..." methods for collection properties fall through if they are given a NULL arg for the item collection.
  • 1.6.0:
    • immutable: You can now have a "modifier" class generated that provides methods to modify the state of an otherwise immutable object anyway.
  • 1.6.1:
    • minor bugfixes
  • 1.6.2:
    • immutable: Introduced alternate collection type when generating immutable collection properties
    • made more names of generated items configurable
  • 1.6.3:
    • Added "fake" mode for immutable, only for test purposes
  • 1.6.4:
    • group-contract: when generating methods that could conflict with each other in cases where two interfaces are used at the same time as generic type parameter boundaries, an extra level of interfaces is declared so that the potentially problematic methods are in their own interface definition which can be omitted in your code if desired.
    • Issue #16 resolved.
    • clone: Resolved an issue with generating the "throws CloneNotSupportedException" declarations. Now they are only generated if actually needed.
    • Put "modifier" generation into separate plugin class.
  • 1.6.5:
    • fluent-builder: Changed logic of static "copyOf" method to allow widening type conversion of input parameter.
  • 1.6.6:
    • fluent-builder: Changed type parameter names to make name conflicts less likely
  • 1.6.7:
    • Fixed a bug in fluent-builder generation that could prevent builder chaining under some circumstances
  • 1.6.8:
    • Integrated a fix from JulianPaoloThiry
    • Improved fluent builder to support building of sub-objects defined in a choice. All possible have a buidler method now, so, for example, in XHTML, instead of doing something like htmlBuilder.withPorH1orH2(H1.builder().withContent("bla").build()).... you can do htmlBuilder.withH1().withContent("bla").end().....
  • 1.6.9:
    • Fixed errors in release workflow
  • 1.6.10:
    • Changes in group-contract plugin when handling XSD input sources.
  • 1.7.0:
    • Modified fluent builder behavior so that it creates a deep copy of all child objects passed to the builder methods, if the child object is an instance of a JAXB-generated class from the same compilation unit or one of its episode-dependencies.
  • 1.8.0:
    • Made behavior introduced in 1.7.0 switchable with command-line parameter, because it isn't desirable in many cases.
    • Improved site and documentation generation
  • 1.9.0:
    • Refactored out common classes to jaxb-plugin-lib module
    • Fixed override of choice expansion builder methods
    • Fixed possible name clashes with choice expansion
  • 1.10.0:
    • Added visitor pattern to meta plugin
    • Added property access via meta plugin
  • 1.11.0:
    • Made "visit" method return "this" for easier chaining.
  • 1.11.1:
    • Fixed bug in constant name generation
  • 1.11.1:
    • Fixed regression bug in builder where non-copied objects were not saved
  • 1.12.0
    • Enable visitor to visit root object
  • 1.13.0
    • Fixed instance access to static field generation in meta plugin
    • Fixed choice expansion to work with collections not only of complexTypes, but of simpleTypes as well
  • 1.14.0
    • Added "visit" Method to generated interfaces.
  • 1.15.0
    • Moved "visit" Method to "Lifecycle" interfaces.
  • 1.16.0
    • Minor bugfixes
  • 1.17.0
    • Fixed issues with modular compilation ("episode") when more than one upstream modules were referenced via the episode mechanism.
  • 1.18.0
    • Fixed issues when generating expanded <choice> builder methods.
    • Fixed issues with visitor pattern for primitive collection properties.
  • 2.0.0
    • Requires Java 8 now
    • Splitting meta and visitor plugins
    • Requires JAXB 2.3 now
  • 2.0.1
    • Reverted JAXBElement handling because of ObjectFactory problems
  • 2.1.0
    • Merged some pull requests to handle documentation annotations

Benutzung

Allgemein

jaxb2-rich-contract-plugin ist ein Plugin für den XJC "XML to Java compiler" der JAXB API, die in allen Java SE-Versionen seit 1.6 enthalten ist. Um das Plugin zu aktivieren, sind folgende Schritte erforderlich:

  • JAR des Plugins zum Klassenpfad des XJC-Compilers hinzufügen.
  • Falls die Standard-JAXB-Version der Compiler-Umgebung kleiner als 2.3 ist, müssen die JAXB-Bibliotheken in Version 2.3 ebenfalls zum Klassenpfad hinzugefügt werden.
  • Kommandozeilenoption zur Aktivierung des gewüschten Plugins zur XJC-Kommandozeile hinzufügen.
  • Die meisten Plugins haben außerdem noch eigene Kommandozeilenoptionen. Diese müssen direkt nach der Aktivierungsoption ("-X...") angegeben werden, um Namenskonflikte zwischen Optionen verschiedener Plugins zu vermeiden.
  • Die Plugins "immutable" und "constrained-properties" schließen sich gegenseitig aus und können nicht beide in einer einzigen Kommandozeile aktiviert werden. Ein Objekt kann nicht gleichzeitig unveränderlich sein und Änderungsnachrichten schicken.

Benutzung mit Apache Maven

Das "maven-jaxb2-plugin" der <build> -Konfiguration hinzufügen. In dessen Konfigurationsabschnitt müssen dann die einzelnen Plugins aktiviert werden. Ebenso wird hier der Klassenpfad so gesetzt, dass bei der Ausführung von XJC das Plugin-JAR jaxb2-rich-contract-plugin im Klassenpfad ist.

Dieses "cheat sheet" gibt alle verfügbaren Plugin-Optionen an und zeigt, wie die Abhängigkeit zum Plugin-JAR in den XJC-Klassenpfad konfiguriert wird:

    <build>
        <plugins>
            <plugin>
                <groupId>org.jvnet.jaxb2.maven2</groupId>
                <artifactId>maven-jaxb2-plugin</artifactId>
                <version>0.14.0</version>
                <executions>
                    <execution>
                        <id>xsd-generate</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <schemaIncludes>
                        <schemaInclude>**/*.xsd</schemaInclude>
                    </schemaIncludes>
                    <strict>true</strict>
                    <verbose>true</verbose>
                    <extension>true</extension>
                    <removeOldOutput>true</removeOldOutput>
                    <args>
                        <arg>-Xconstrained-properties</arg>
                            <arg>-constrained=y</arg>
                            <arg>-bound=y</arg>
                            <arg>-setterThrows=n</arg>
                            <arg>-generateTools=y</arg>
                        <arg>-Xclone</arg>
                            <arg>-cloneThrows=y</arg>
                        <arg>-Xcopy</arg>
                            <arg>-partial=y</arg>
                            <arg>-generateTools=y</arg>
                            <arg>-constructor=y</arg>
                            <arg>-narrow=n</arg>
                            <arg>-selectorClassName=Selector</arg>
                            <arg>-rootSelectorClassName=Select</arg>
                        <arg>-Xgroup-contract</arg>
                            <arg>-declareSetters=y</arg>
                            <arg>-declareBuilderInterface=y</arg>
                            <arg>-supportInterfaceNameSuffix=Lifecycle</arg>
                            <arg>-upstreamEpisodeFile=META-INF/jaxb-interfaces.episode</arg>
                            <arg>-downstreamEpisodeFile=/META-INF/jaxb-interfaces.episode</arg>
                        <arg>-Ximmutable</arg>
                            <arg>-fake=n</arg>
                            <arg>-overrideCollectionClass=null</arg>
                            <arg>-constructorAccess=public</arg>
                        <arg>-Xmodifier</arg>
                            <arg>-modifierClassName=Modifier</arg>
                            <arg>-modifierMethodName=modifier</arg>
                        <arg>-Xfluent-builder</arg>
                            <arg>-rootSelectorClassName=Select</arg>
                            <arg>-newBuilderMethodName=builder</arg>
                            <arg>-newCopyBuilderMethodName=newCopyBuilder</arg>
                            <arg>-copyToMethodName=copyTo</arg>
                            <arg>-builderFieldSuffix=_Builder</arg>
                            <arg>-generateTools=y</arg>
                            <arg>-narrow=n</arg>
                            <arg>-copyPartial=y</arg>
                            <arg>-selectorClassName=Selector</arg>
                            <arg>-builderClassName=Builder</arg>
                            <arg>-builderMethodPrefix=with</arg>
                            <arg>-builderInterfaceName=BuildSupport</arg>
                            <arg>-copyAlways=n</arg>
                            <arg>-copyOfBuilder=y</arg>
                            <arg>-buildMethodName=build</arg>
                            <arg>-endMethodName=end</arg>
                            <arg>-generateJavadocFromAnnotations=n</arg>
                        <arg>-Xmeta</arg>
                            <arg>-generateTools=y</arg>
                            <arg>-extended=n</arg>
                            <arg>-camelCase=n</arg>
                            <arg>-metaClassName=PropInfo</arg>
                            <arg>-allowSet=y</arg>
                            <arg>-visitMethodName=visit</arg>
                    </args>
                    <plugins>
                        <plugin>
                            <groupId>net.codesup.util</groupId>
                            <artifactId>jaxb2-rich-contract-plugin</artifactId>
                            <version>1.18.0</version>
                        </plugin>
                    </plugins>
                    <dependencies>
                        <!-- Put this in if your default JAXB version is 2.2 or lower,
                        or if &quot;tools.jar&quot; isn't in your classpath -->
                        <dependency>
                            <groupId>org.glassfish.jaxb</groupId>
                            <artifactId>jaxb-runtime</artifactId>
                            <version>2.3</version>
                        </dependency>
                        <dependency>
                            <groupId>org.glassfish.jaxb</groupId>
                            <artifactId>jaxb-core</artifactId>
                            <version>2.3</version>
                        </dependency>
                        <dependency>
                            <groupId>org.glassfish.jaxb</groupId>
                            <artifactId>jaxb-xjc</artifactId>
                            <version>2.3</version>
                        </dependency>
                    </dependencies>
                </configuration>
            </plugin>
        </plugins>
    </build>

Hinweis: Das Flag <extension/> muss auf "true" gesetzt sein, damit XJC überhaupt plugins akzeptiert.

Hinweis: jaxb2-rich-contract-plugin implementiert JAXB und XJC APIs in der Version 2.3. Falls Sie mit einem älteren JDK arbeiten, müssen sie diese Bibliotheken ebenfalls zum Klassenpfad hinzufügen. Wie dies gemacht wird, ist im <dependencies>-Element oben zu sehen.

constrained-properties

Motivation

Many GUI applications use data binding to connect the data model to the view components. The JavaBeans standard defines a simple component model that also supports properties which send notifications whenever the are about to be changed, and there are even vetoable changes that allow a change listener to inhibit modification of a property. While the JAvaBeans standard is a bit dated, data binding and property change notification can come in handy in many situations, even for debugging or reverse-engineering existing code, because you can track any change made to the model instance.

Funktion

constrained-properties generates additional code in the property setter methods of the POJOs generated by XJC that allow PropertyChangeListeners and VetoableChangeListeners to be attached to any instance of a XJC-generated class.

Currently, indexed properties are NOT supported in the way specified by JavaBeans, but instead, if a property represents a collection, a collection proxy class is generated that supports its own set of collection-specific change notifications, vetoable and other. This decision has been made because by default XJC generates collection properties rather than indexed properties, and indexed properties as mandated by JavaBeans are generally considered "out of style".

Enschränkungen

  • The JavaBeans standard is only loosely implemented in the generated classes.
  • Indexed Properties as defined in JavaBeans are not supported.
  • The CollectionChange behavior implemented by the classes is not yet documented and non-standard.

Aktivierung

-Xconstrained-properties

Optionen

-constrained={y|n} (y)

Erzeuge "constrained properties", die durch das Werfen einer Exception eine Änderung ihres Zustandes unterbinden können.

-bound={y|n} (y)

Erzeuge "bound properties", die die Änderung ihres Zustandes als Event weitermelden.

-setterThrows={y|n} (n)

Wenn Constrained Properties verwendet werden, soll eine PropertyVetoException bei unerlaubter Zustandsänderung geworfen werden. Wenn dies auf "no" gesetzt ist, wird stattdessen eine "RuntimeException" erzeugt.

-generateTools={y|n} (y)

Generiere die Hilfsklassen, die zur Realisierung der nicht-standardkonformen "Collection Changed" events gebraucht werden, als Quelltext.

clone

Motivation

Another way to create a deep copy of an object tree. This adheres to the java.lang.Cloneable contract, but isn't as versatile as -Xcopy.

Funktion

The clone plugin generates a deep clone method for each of the generated classes, based on the following assumptions:

  • Objects implementing java.lang.Cloneable and are cloneable by their "clone" Method.
  • Objects not implementing java.lang.Cloneable or primitive types are assumed to be immutable, their references are copied over, they are not cloned.

Bugs

The -cloneThrows option should in fact never have existed.

Enschränkungen

There is currently no way for the plugin to determine whether an object in the object graph that isn't cloneable actually is immutable so its reference can be copied. So, there is no guarantee that cloned object graphs are really independent of each other, as mandated by the java.lang.Cloneable contract.

Aktivierung

-Xclone

Optionen

-cloneThrows={y|n} (y)

'CloneNotSupportedException' in der Methodensignatur von 'clone()' deklarieren (yes), oder 'throws' weglassen und evtl. Exception intern ignorieren (no).

copy

Motivation

Sometimes it is necessary to create a deep copy of an object. There are various approaches to this. The "copy" plugin defines its own interface, contract, and definitions that are somewhat different from the standard java "java.lang.Cloneable" contract. The entry point generated in the source code is called createCopy, there are optionally also copy constructors.

Funktion

The copy plugin generates a deep clone method for each of the generated classes, based on the following assumptions:

  • Instances of any other classes implementing the com.kscs.util.jaxb.Copyable interface are copyable by the same semantics as "this".

  • Objects implementing java.lang.Cloneable and not throwing "CloneNotSupportedException" are also reliably cloneable by their "clone" Method.

  • Objects not implementing java.lang.Cloneable or primitive types are assumed to be immutable, their references are copied over, they are not cloned.

  • Optionally, generates a "partial createCopy" method that takes a PropertyTree instance which represents a specification of the nodes in the object tree to copy. The PropertyTree is built up by an intuitive builder pattern:

      final PropertyTree excludeEmployees = PropertyTree.builder().with("company").with("employees").build();
    
  • There is also a type-safe way to build a PropertyPath instance by using a generated classes' Selector sub structure. The following will generate the same selection as above:

      final PropertyTree excludeEmployees = Business.Select.root().company().employees().build()
    

Then, you would partially clone an object tree like this:

	final BusinessPartner businessPartnerCopy = businessPartner.createCopy(excludeEmployees, PropertyTreeUse.EXCLUDE);

Which is the same as

	final BusinessPartner businessPartnerCopy = businessPartner.copyExcept(excludeEmployees);

This way, the copy of the original businessPartner will have no employees attached to the contained company. It is also possible to copy only a specific subset of the original object tree, excluding everything else. The inverse result of the above would be generated by:

	final BusinessPartner businessPartnerCopy = businessPartner.createCopy(excludeEmployees, PropertyTreeUse.INCLUDE);

or

	final BusinessPartner businessPartnerCopy = businessPartner.copyOnly(excludeEmployees);

which will result in a businessPartnerCopy where every property is set to null, except the company property, and in the attached company object, every property is null except "employees".

This works for single and multi-valued properties, where for multi-valued properties, the property tree applies to all elements of the list of values in the same way. As of yet, there is no way to make a tree apply only to specific indexes in generated lists.

Enschränkungen

  • The -narrow option is a somewhat special use case and should be used carefully.

Aktivierung

-Xcopy

Optionen

-partial={y|n} (y)

Generiert zusätzlich eine 'createCopy()'-Methode und einen Konstruktor (wenn "-constructor=yes"), mit dem sich Objekte partiell kopieren lassen. Dabei wird ein PropertyPath-Objekt mitgegeben, welches die zu kopierenden Knoten des Objektbaumes angibt.

-generateTools={y|n} (y)

Generiere Hilfsklassen als Quelltext (y). Wenn dies ausgeschaltet ist, muss sich das Plugin-JAR zur Laufzeit im Klassenpfad der generierten Klassendefinitionen befinden.

-constructor={y|n} (y)

Erzeugt einen Copy-Konstruktor für jede generierte Klasse des XSD-Modells.

-narrow={y|n} (n)

Für untergeordnete Knoten im zu kopierenden Objektbaum werden ebenfalls die Copy-Konstruktoren der deklarierten Typen verwendet, soweit diese vorhanden sind und die Typen der entsprechenden Instanzen ebenfalls aus dem XSD-Model generierte Klassen sind. Dies erzeugt eine möglichst "schmale" Kopie des Ausgangsobjekts, was in bestimmten Fällen nützlich sein kann. Ein Unterknoten, dessen Typ nicht im aktuellen XSD-Modell deklariert ist, wird immer wie bei der 'createCopy()'-Methode kopiert. Ist diese Option "no", gilt dies auch für generierte Typen.

-selectorClassName=<string> (Selector)

Name der generierten inneren "Selector" Builder-Klasse, die intern zum Aufbau des Property-Baums für das partielle Kopieren benutzt wird. Diese Einstellung gilt auch für das "Fluent Builder"-Plugin, wenn dieses zusätzlich aktiv ist und dort "copy-partial=y" eingestellt ist.

-rootSelectorClassName=<string> (Select)

Name der generierten inneren "Select" -Klasse, die vom aufrufenden Code als Einstieg in den Aufbau eines Property-Baumes für das partielle Kopieren verwendet werden kann. Diese Einstellung gilt auch für das "Fluent Builder"-Plugin, wenn dieses zusätzlich aktiv ist und dort "-copy-partial=y" eingestellt ist.

group-contract

Motivation

In most object-oriented programming languages, there are constructs to define a "contract", that concrete implementations of complex types will implement. In Java, for example, there is the interface, in Scala there are "traits", and so on. The XML Schema Definition Language (XSD) in contrast, has no explicit construct to ensure a complex type meets a pre-defined contract. There are, however, the group and attributeGroup elements, that could be considered a way to achieve just that: A complexType that uses a <group> or an <attributeGroup> will expose the properties defined in these group definitions. Looking at it that way, you could say that the complexType "implements" the contract defined by the group or attributeGroup.

Funktion

The group-contract plugin now tries to model that case in the generated source code. For every groupand attributeGroup definition in the XSD model (or in any upstream XSD model that is included via the "episode" mechanism, for that matter), it generates an interface definition with all the getter, and optionally setter, methods of the properties defined via the group or attributeGroup definition.

Then, it declares every class that was generated from a complexType that uses the group or attributeGroup as implementing just that interface. This way, all classes generated from XSD complexTypes that use the same group definitions, will share a common contract and can be treated in a common way by client code.

If the "fluent-builder" plugin is also activated, the interface definition can optionally include the declarations of the "with..." and "add..." methods of the generated builder class as a nested interface declaration, so you can even rely on a common "builder" contract for classes using the same group and attributeGroup definitions.

For example, you may wish to add "XLink" functionality to your generated classes. If the group-contract plugin is activated, you can define a complexType in XSD that supports the "simple" attributes by adding to its XSD definition:

<complexType name="some-type">
	.... (model group of the type...)
	<attributeGroup ref="xlink:simpleAttrs"/>
</complexType>

Which will generate a class something like:

public class SomeType implements SimpleAttrs {
...

And an interface definition like:

public interface SimpleAttrs {
	String getHref();
	void setHref(final String value);
	// ... more properties ...

	// this part is generated only if fluent-builder is also active
	interface BuildSupport<TParentBuilder >{
            public SimpleAttrs.BuildSupport<TParentBuilder> withHref(final String href);
            //... more properties ...
	}
}

Similar effects could be achieved by subclassing complexTypes, but since there is no multiple inheritance, inheritance hierarchies can get overly complex this way, and inheritance is less flexible than interface implementations.

Note: The group-contract plugin supports JAXB modular compilation, i.e. the "episode" mechanism implemented in the JAXB reference impplementation. However, due to the lack of extensibility of the current default episode data structures and processing, this plugin has to manage its own "episode" file. There are two command line options to control the names of the "upstream" episode file, i.e. the file name the plugin should look for when using other modules, and the "downstream" file, i.e. the file name that should be generated for use by other modules.

Bugs

Currently none known

Aktivierung

-Xgroup-contract

Optionen

-declareSetters={y|n} (y)

Auch die Setter-Methoden in den generierten Interfaces deklarieren. Wenn nein, werden nur Getter deklariert.

-declareBuilderInterface={y|n} (y)

Wenn das "fluent builder plugin" (-Xfluent-builder) ebenfalls aktive ist, generiere auch Interfaces für die inneren Builder-Klassen.

-supportInterfaceNameSuffix=<string> (Lifecycle)

Methoden, die zu Typkonflikten führen können, wenn zwei oder mehr interfaces aus diesem Generat gleichzeitig(mit "&") als Grenzen generischer Typparameter verwendet werden, werden in ein eigenes Interface ausgelagert, dessen Name dann mit dem angegebenen Wortbestandteil endet.

-upstreamEpisodeFile=<string> (META-INF/jaxb-interfaces.episode)

Suche die angegebene "episode"-Datei (Resource-Pfad), um Informationen über interfaces zu erhalten, die in Modulen definiert wurden, von denen dieses hier abhängig ist (siehe "-episode"-Mechanismus in der XJC-Dokumentation).

-downstreamEpisodeFile=<string> (/META-INF/jaxb-interfaces.episode)

Generiere "episode"-Datei für abhängige Module an der angegebene Stelle (Resource-Pfad).

immutable

Motivation

Generally it is advisable to make your business classes immutable as much as possible, to minimise side effects and allow for functional programming patterns.

Funktion

This plugin simply makes all "setXXX" methods "protected", thus preventing API consumers to modify state of instances of generated classes after they have been created. This only makes sense together with another plugin that allows for initialization of the instances, like e.g. the included fluent-builder plugin. For collection-valued properties, -Ximmutable wraps all collections in a Collections.unmodifiableCollection, so collections are also made immutable. Because JAXB serialization has a number of constraints regarding the internals of JAXB serializable objects, it wasn't advisable to just remove the setter methods or replace the collections with unmodifiable collections. So, a bit of additional code will be created that leaves the old "mutable" structure of the class intact as much as is needed for JAXB, but modifies the public interface so objects appear immutable to client code.

Enschränkungen

  • Access level "protected" may not be strict enough to prevent state changes.
  • If you activate plugins like "fluent-api" or the like, these plugins may circumvent the protection provided by the immutable plugin.

Aktivierung

-Ximmutable

Optionen

-fake={y|n} (n)

Nur für Test und Debug: Es wird nichts wirklich unveränderlich gemacht, aber das Plugin bleibt aktiv.

-overrideCollectionClass=<string> (null)

Modify collection getters to be declared to return a custom type implementing java.lang.Iterable instead of List.

-constructorAccess=<string> (public)

Setzt die Sichtbarkeit des von JAXB geforderten argumentlosen Konstruktors auf den angegebenen Wert ("public", "private", "protected", "default"). Die JAXB-Spezifikation fordert eigentlich, dass der Konstruktor "public" sein soll, aber in vielen Implementierungen funktioniert auch "protected". Diese Option wurde eingeführt, da es normalerweise wenig sinnvoll ist, ein leeres Objekt zu erzeugen, das danach nicht mehr verändert werden kann. Dennoch ist dies nicht standardkonform und daher mit Vorsicht zu benutzen.

modifier

Motivation

Generell ist es vorteilhaft, Anwendungslogik so zu implementieren, dass Objekte in der Regel nach der Initialisierung in ihrem Zustand unveränderlich sind. In traditionellen Programmiersprachen wie z.B. Java bleibt dies jedoch oftmals ein akademischer Ansatz, da oft auf bestehendem Code und bestehenden Bibliotheken aufgesetzt werden muss, die ein derartiges Programmiermodell nicht oder nur unzulänglich unterstützen.

Das modifier-Plugin schafft eine Möglichkeit, einerseits (z.B. durch das immutable-Plugin) die allgemeine Schnittstelle einer Klasse so zu definieren, dass darüber keine Zustandsänderungen am Objekt möglich sind, aber gleichzeitig für bestimmte Szenarien eine explizit abzurufende Referenz bereit zu stellen, über die das Objekt dennoch einfach verändert werden kann.

Der Einsatz dieses Plugins ist hauptsächlich für eine Übergangszeit während der Refaktorierung von existierendem Code vorgesehen, sodass zur Compilezeit die Stellen im Code deutlich werden, die zustandsveränderliche Objekte voraussetzen. Ziel sollte es dann sein, dieses Plugin irgendwann im eigenen Projekt abschalten zu können.

Funktion

Es wird eine innere Klasse generiert, die öffentliche setXXX-Methoden und getXXX-Methoden für Collections enthält, wobei schreibbare Collection-Instanzen zurückgegeben werden.

Wenn das group-contract-Plugin ebenfalls aktiviert ist, werden diese Konstrukte auch in den Interfaces erzeugt.

Aktivierung

-Xmodifier

Optionen

-modifierClassName=<string> (Modifier)

Name der generierten Mutator-Klasse

-modifierMethodName=<string> (modifier)

Name der generierten methode zum Abruf einer Instanz der Mutator-Klasse

fluent-builder

Motivation

There already is the widely used "fluent-api" plugin for XJC. That, however isn't a real builder pattern since there is no distinction between initialization and state change in fluent-api.

fluent-builder now creates a real "Builder" pattern, implemented as an inner class to the generated classes.

Funktion

fluent-builder creates a builder class with a "fluent interface", and a number of methods to create builder instances. The builder class is generated as a static inner class to all of the value object classes generated with XJC. It supports the "episode" mechanism to generate builder code seamlessly across multiple compilation schema modules.

Example use in code:

    MyElement newElement = MyElement.builder().withPropertyA(...).withPropertyB(...).addCollectionPropertyA(...).build();

Additional Features

"Choice Expansion"

In standard JAXB, if you define a <choice> group in an XSD complexType definition with cardinality "many", the generated code will only contain a generic collection of "java.lang.Object" type, named something like "AorBorC...".

However, fluent-builder will determine exactly which types are actually possible in this collection, and will generate individual "addXXX" methods for each of them.

So, imagine you have generated code from the XHTML 1.0 schema, and you wish to use fluent-builder to generate an XHTML document programmatically. Now, again imagine you have already created the "html" and "head" elements, and you are about to populate the "body" eith a table.

Without fluent-builder, you would do something like:

Body body = new Body();
Table table = new Table();
body.getPorH2orH2().add(table);
Tr tr = new Tr();
table.getTheadOrTrOrTdata().add(tr);
Td td = new Td();
tr.getTd().add(td);
td.setContent("Hello World");

With fluent-builder, you can achieve the same more intuitively:

Body.builder().addTable().addTr().addTd().withContent("Hello World").end().end().end().build();
Object Deep-Copy strategies and Behaviors

In addition, new instances can be created as copies of existing instances using the builder, with an optional modification by other builder methods:

Static Deep Copy
    MyElement newElement = MyElement.copyOf(oldElement).withPropertyA(...).withPropertyB(...).build();

Or, similar to the java clone() method, creating a runtime copy of a reference:

Polymorphic Deep Copy
	MyObj myObj = oldObj.newCopyBuilder().with... .build();
Partial Copy (Static and Polymorphic)

The "partial" copy introduced in the "copy" plugin will work here as well, with both static (copyOf()) as well as polymorphic (newCopyBuilder()) behaviors:

    PropertyTree selection = MyElement.Select.root().propertyA().propertyAB().build();
    MyElement newElement = MyElement.copyExcept(oldElement, selection).withPropertyA(...).withPropertyB(...).build();
	MyObj myObj = oldObj.newCopyBuilder(selection, PropertyTreeUse.EXCLUDE).with.... .build();
Static vs. Polymorphic Deep Copy

The difference between copyOf() and newCopyBuilder() is their respective polymorphic behavior. newCopyBuilder() always returns a builder instance that corresponds to the current runtime type of the object upon which the newCopyBuilder() method was invoked. I.e., using newCopyBuilder(), you always get an object of exactly the same type as before as soon as you call build().

In contrast, MyClass.copyOf(), being a static method, always returns an object of the class on which it is called, MyClass in this case. You can pass an object of any base type (from the same XSD model or one referenced via "episode") or any derived type of MyClass to copyOf(), and you still get an instance of MyClass as soon as you call build(). If you pass an instance of a more general class than MyClass to MyClass.copyOf(), the generated code will only copy the fields that exist in the argument object, and will leave all additional fields uninitialized. You should then initialize them with the other builder methods.

Chained Builder Support

Often, properties of generated classes represent containment or references to generated classes in the same model. The fluent-builder plugin lets you initialise properties of such a type (and of types declared in upstream modules via the "episode" feature) - if it isn't an abstract type - by using sub-builders ("chained" builders) in the following way, given that both A and B are types defined in the XSD model, and A has a property of type B, and B has three properties of type String, x,y, and z:

    A newA = A.builder().withB().withX("x").withY("y").withZ("z").end().build();

Of course, this plugin is most useful if immutable is also activated.

Javadoc genration from schema annotations

By default xjc will add class level Javadoc content from the xs:annotation/xs:documentation element of the corresponding named/anonymous complex type or root element. If you enable generateJavadocFromAnnotations fluent-builder will additionally generate javadoc comments for class getters/setters and builder add/with methods. This enables you to add rich documentation to the schema that will also be available in the JAXB generated code. The content of the <xs:documentaion> element will be added to the head of the existing javadoc comment section as a new paragraph.

Class level Javadoc

Class level Javadoc comments are generated by xjc from anonymous compex types as follows:

  <element name="root-element">
    <complexType>
      <annotation>
        <documentation>This is my Anonymous complex type annotation.</documentation>
      </annotation>
      <sequence>
        <element name="child-element" type="string">

This will produce Javadoc similar to:

/**
 * This is my Anonymous complex type annotation.
 * 
 * <p>Java class for anonymous complex type.
 * ...
 */
 // ...
 public class RootElement implements Cloneable

Class level javadoc comments are also generated from named complex types as follows:

  <complexType name="some-complex-type">
    <annotation>
      <documentation>This is my named complex type annotation</documentation>
    </annotation>
    <sequence>
      <element name="some-element" type="string">

This will produce Javadoc similar to:

/**
 * This is my named complex type annotation
 * 
 * <p>Java class for some-complex-type complex type.
 * ...
 */
 // ...
 public class SomeComplexType implements Cloneable
Method level Javadoc

Method level Javadoc will be added to the get.../set... methods that corresponds to the schema element or attribute that contains the annotation/documentation element. It will also be added to the with.../add... builder methods.

For example, the schema annotation should be as follows:

    <sequence>
      <element name="some-element" type="string">
        <annotation>
          <documentation>This is my element annotation</documentation>
        </annotation>
      </element>

This will produce java code in the corresponding class along the lines of:

    /**
     * This is my element annotation
     * <P>
     * Gets the value of the someElement property.
     * ...
     */
    public String getSomeElement() {
        return someElement;
    }

    /**
     * This is my element annotation
     * <P>
     * Sets the value of the someElement property.
     * ...
     */
    protected void setSomeElement(String value) {
        this.someElement = value;
    }

And java code in the corresponding Builder class as follows:

        /**
         * This is my element annotation
         * <P>
         * Sets the new value of "someElement" (any previous value will be replaced)
         * ...
         */
        public SomeComplexType.Builder<_B> withSomeElement(final String someElement) {
            // ...
        }

Enschränkungen

  • It generates a large amount of code.
  • Note: Shared builder instances are NOT thread-safe by themselves.

Aktivierung

-Xfluent-builder

Optionen

-rootSelectorClassName=<string> (Select)

Name der generierten inneren "Select" -Klasse, die vom aufrufenden Code als Einstieg in den Aufbau eines Property-Baumes für das partielle Kopieren verwendet werden kann. Diese Einstellung wird nur dann berücksichtigt, wenn das "Deep Copy"-Plugin nicht aktiv ist, und "copy-partial=y" ist. Ansonsten gilt die Einstellung des "Deep Copy"-Plugins.

-newBuilderMethodName=<string> (builder)

Name der generierten statischen Methode zum Erzeugen eines neuen Builders. Kann hier gesetzt werden, um Namenskonflikte zu lösen.

-newCopyBuilderMethodName=<string> (newCopyBuilder)

Name der generierten Instanzmethode zum Erzeugen eines neuen Builders, der mit dem von dieser Instanz kopierten Zustand initialisiert ist.

-copyToMethodName=<string> (copyTo)

Name der generierten Methode zum kopieren des internen Zustands dieses Builders auf einen anderen Builder.

-builderFieldSuffix=<string> (_Builder)

Suffix, das an den Namen der generierten Sub-Builder Instanzvariablen angefügt wird.

-generateTools={y|n} (y)

Generiere Hilfsklassen als Quelltext. Wenn dies ausgeschaltet ist, muss sich das Plugin-JAR zur Laufzeit im Klassenpfad der generierten Klassendefinitionen befinden.

-narrow={y|n} (n)

Für untergeordnete Knoten im zu kopierenden Objektbaum werden ebenfalls die Copy-Konstruktoren der deklarierten Typen verwendet, soweit diese vorhanden sind und die Typen der entsprechenden Instanzen ebenfalls aus dem XSD-Model generierte Klassen sind. Dies erzeugt eine möglichst "schmale" Kopie des Ausgangsobjekts, was in bestimmten Fällen nützlich sein kann. Ein Unterknoten, dessen Typ nicht im aktuellen XSD-Modell deklariert ist, wird immer wie bei der 'clone()'-Methode kopiert. Ist diese Option "no", gilt dies auch für generierte Typen.

-copyPartial={y|n} (y)

Generiert zusätzlich eine 'copyOf()'-Methode mit der sich Objekte partiell kopieren lassen. Dabei wird ein PropertyTree-Objekt mitgegeben, welches die zu kopierenden Knoten des Objektbaumes angibt.

-selectorClassName=<string> (Selector)

Name der generierten inneren "Selector" Builder-Klasse, die intern zum Aufbau des Property-Baums für das partielle Kopieren benutzt wird. Diese Einstellung wird nur dann berücksichtigt, wenn das "Deep Copy"-Plugin nicht aktiv ist, und "copy-partial=y" ist. Ansonsten gilt die Einstellung des "Deep Copy"-Plugins.

-builderClassName=<string> (Builder)

Name der generierten inneren Builder-Klasse. Kann hier gesetzt werden, um Namenskonflikte zu lösen.

-builderMethodPrefix=<string> (with)

Prefix, das vor den Namen der Buildermethoden angehängt wird.

-builderInterfaceName=<string> (BuildSupport)

Name des generierten inneren Builder-Interfaces. Kann hier gesetzt werden, um Namenskonflikte zu lösen.

-copyAlways={y|n} (n)

Ist diese Option 'yes', werden alle Variablen-Methoden, die JAXB-generierte Objekte akzeptieren, so generiert, dass die übergebenen Objekte kopiert werden.

-copyOfBuilder={y|n} (y)

Ist diese Option 'yes', wird eine copyOf Methode für den fluent-builder generiert.

-buildMethodName=<string> (build)

Name der generierten "build"-Methode, die das gebaute Objekt zurückliefert.

-endMethodName=<string> (end)

Name der generierten "end"-Methode, die einen sub-Builder beendet.

-generateJavadocFromAnnotations={y|n} (n)

TODO

meta

Motivation

Sometimes, you need information about the properties of a class, or you wish to have a constant for the names of properties. The "meta" plugin creates an inner class (the name of which can be controlled by a command-line option), and adds a constant field for each property. If the -extended=y command-line option is specified, these constants will hold instances of the PropertyInfo class, on which the name, type, multiplicity (collection or not) and default value (from XSD) are exposed. Without -extended, the constants are simply string constants holding the property names.

In Version 1.10 wurde neu ein "Visitor"-Muster eingeführt, über das sich der gesamte Objektgraph durchlaufen lässt.

Aktivierung

-Xmeta

Optionen

-generateTools={y|n} (y)

Generiere die Hilfsklasse zur Darstellung der erweiterten Metadaten als Quelltext. Wenn hier "n" angegeben wird und "extended=y", so muss das plugin JAR zur Laufzeit im Klassenpfad der client-Anwendung sein.

-extended={y|n} (n)

Generiere erweiterte Metadaten für jedes Property: Name, Typ, Multiplizität, Standardwert

-camelCase={y|n} (n)

Namen der Konstanten wie Feldnamen generieren, nicht nach Java-Konstanten-Konvention.

-metaClassName=<string> (PropInfo)

Name der generierten inneren Metainfoklasse.

-allowSet={y|n} (y)

Generiere eine Möglichkeit, den Wert eines Propertys über die Metadaten zu ändern.

-visitMethodName=<string> (visit)

Name der Methode, mit der ein Visitor durch das Objekt geschickt werden kann.