Giter VIP home page Giter VIP logo

jaxb-xew-plugin's Introduction

JAXB @XmlElementWrapper Plugin

Description

This JAXB plugin utilises the power of @XmlElementWrapper annotation. Originally xjc trends to create wrapper classes which are the containers for collections. This plugin goes through all properties to find ones which can be represented in the model in more optimal way.

The problem origin in details

To illustrate the problem let's take the following XSD:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
	xmlns:xs="http://www.w3.org/2001/XMLSchema"
	xmlns:xml="http://www.w3.org/XML/1998/namespace"
	elementFormDefault="qualified">

	<xs:element name="order">
		<xs:complexType>
			<xs:sequence>
				<xs:element ref="items" />
			</xs:sequence>
		</xs:complexType>
	</xs:element>

	<xs:element name="items">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="item" type="xs:string" maxOccurs="unbounded" />
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

From this XSD by default xjc will generate two classes:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = { "items" })
@XmlRootElement(name = "order")
public class Order {

	@XmlElement(required = true)
	protected Items	items;

	public Items getItems() {
		return items;
	}

	public void setItems(Items value) {
		this.items = value;
	}
}

and

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = { "item" })
@XmlRootElement(name = "items")
public class Items {

	@XmlElement(required = true)
	protected List<String>	item;

	public List<String> getItem() {
		if (item == null) {
			item = new ArrayList<String>();
		}
		return this.item;
	}
}

So to access a particular item one need to write a but clumsy code order.getItems().getItems().get(itemIndex). The solution is to use @XmlElementWrapper which cures exactly this case. The result will be only one class with direct access to items:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = { "items" })
@XmlRootElement(name = "order")
public class Order {

	@XmlElementWrapper(name = "items", required = true)
	@XmlElement(name = "item")
	protected List<String>	items;

	public List<String> getItems() {
		if (items == null) {
			items = new ArrayList<String>();
		}
		return items;
	}

	public void setItems(List<String> items) {
		this.items = items;
	}
}

Usage

The plugin is used together with the xjc from the command line or from an Ant task or via maven-jaxb2-plugin.

The following options are applicable for plugin:

Option Comment
-Xxew Activate the XML Element Wrapper plugin
-Xxew:include filename Specify a filename with candidate classes to include in the compilation.
-Xxew:exclude filename Specify a filename with candidate classes to exclude from the compilation.
-Xxew:summary filename Specify a filename to contain summary information for the compilation.
-Xxew:collection FQCN Specify the class name of the collection type to use.
-Xxew:instantiate [lazy|early] Specify when the collection class should be instantiated.
-Xxew:delete Delete candidate classes having been replaced during compilation.

Episode file

For correct generation of episode file the corresponding XJC options should follow -Xxew, for example:

-Xxew ... -episode <file>

This will trigger episode plugin after Xew plugin and episode file will be correctly generated.

fluent-api and value-constructor plugins

These plugins should be activated after Xew plugin:

-Xxew ... -Xfluent-api -Xvalue-constructor

Otherwise (if they are activated before) Xew plugin cannot revert/complement the changes they made and compile-time error is guaranteed.

Ant task

First you need to download the plugin jar (for example, from Maven repository) and put it to your project lib folder.

To use the plugin from Ant you will need something like the following in your build file:

<taskdef name="xjc" classname="com.sun.tools.xjc.XJCTask">
	<classpath>
		<fileset dir="${lib}/jaxb" includes="*.jar" />
		<fileset dir="lib" includes="jaxb-xew-plugin.jar" />
	</classpath>
</taskdef>

<xjc destdir="${src-generated}" package="dk.conspicio.example.xml2code.v2">
	<arg value="-Xxew" />
	<arg value="-Xxew:summary ${build}/xew-summary.txt" />
	<arg value="-Xxew:instantiate lazy" />
	<schema dir="xsd" includes="*.xsd" />
	<binding dir="xsd" includes="*.xjb" />
</xjc>

Maven

maven-jaxb2-plugin

Note: maven-jaxb2-plugin prior to v0.8.0 was compiled against JAXB XJC API which is not compatible with this plugin. Version 0.8.1 is guaranteed to work, versions 0.8.2 and 0.8.3 should also work fine.

<plugin>
	<groupId>org.jvnet.jaxb2.maven2</groupId>
	<artifactId>maven-jaxb2-plugin</artifactId>
	<version>0.8.1</version>
	<executions>
		<execution>
			<phase>generate-sources</phase>
			<goals>
				<goal>generate</goal>
			</goals>
			<configuration>
				<verbose>true</verbose>
				<generateDirectory>${project.build.sourceDirectory}</generateDirectory>
				<schemaDirectory>xsd</schemaDirectory>
				<removeOldOutput>false</removeOldOutput>
				<episode>false</episode>

				<extension>true</extension>
				<args>
					<arg>-no-header</arg>
					<arg>-Xxew</arg>
					<arg>-Xxew:instantiate lazy</arg>
					<arg>-Xxew:delete</arg>
				</args>
				<plugins>
					<plugin>
						<groupId>com.github.jaxb-xew-plugin</groupId>
						<artifactId>jaxb-xew-plugin</artifactId>
						<version>1.0</version>
					</plugin>
				</plugins>
			</configuration>
		</execution>
	</executions>
</plugin>

jaxb2-maven-plugin

Note: jaxb2-maven-plugin v1.5 was compiled against JAXB XJC API v2.1.13 which is not compatible with this plugin, thus additional dependency is needed to be added to plugin classpath.

<plugin>
	<groupId>org.codehaus.mojo</groupId>
	<artifactId>jaxb2-maven-plugin</artifactId>
	<version>1.5</version>
	<executions>
		<execution>
			<phase>generate-sources</phase>
			<goals>
				<goal>xjc</goal>
			</goals>
			<configuration>
				<verbose>true</verbose>
				<outputDirectory>${project.build.sourceDirectory}</outputDirectory>
				<schemaDirectory>xsd</schemaDirectory>
				<clearOutputDir>false</clearOutputDir>

				<extension>true</extension>
				<arguments>-no-header -Xxew -Xxew:instantiate lazy -Xxew:delete</arguments>
			</configuration>
		</execution>
	</executions>
	<dependencies>
		<dependency>
			<groupId>com.github.jaxb-xew-plugin</groupId>
			<artifactId>jaxb-xew-plugin</artifactId>
			<version>1.0</version>
		</dependency>
		<!-- 
		 | We need to update the jaxb-xjc plugin version from 2.1.13 to the 2.2.4-1 version 
		 | used by the jaxb-xew-plugin (version 2.1.13 which does not have the required 
		 | method com.suun.codemodel.JAnnotatable.annotations()Ljava/util/Collection).
		 -->
		<dependency>
			<groupId>com.sun.xml.bind</groupId>
			<artifactId>jaxb-xjc</artifactId>
			<version>2.2.4-1</version>
		</dependency>
	</dependencies>
</plugin>

You can find more examples of this plugin in samples directory (including how to call this plugin from jaxws:wsimport).

What's new

v1.1

  • Plugin is re-worked. Bugs fixed (#1, #3, #6, #7). Some functionality is possible only by accessing private fields, so Xew plugin may not work in security-managed environment.
  • Testing framework introduced. XSDs in com/sun/tools/xjc/addon/xew/ directory can be referred as collection of examples.
  • Logging is done via commons-logging. Log level is configurable like this mvn -Dorg.apache.commons.logging.simplelog.defaultlog=DEBUG.

v1.0

The original code of Bjarne Hansen, with some fixes.

Contribution

If you have time and desire to contribute to this project you can do it in many ways:

  • Improve this very documentation.
  • Implement Unit tests.
  • Provide more samples.

Development

Everybody is very welcomed to send patches by email. But the best way would be:

  • Fork the repository.
  • Apply the formatting rules (the ones for Eclipse can be found in dist folder).
  • Create a ticket in bugtracker. If applicable attach XSD that demonstrates the problem to the issue.
  • Create a branch referring the ticket number (git branch issue-22).
  • Do the changes.
  • Commit to your own fork, mentioning the ticket number in commit message (Implemented nice feature (fixes #22)). Check here the commit message syntax sugar.
  • Request for pull.

If you provide the code in any way you automatically agree with a project license.

Code style

  • There are no specific coding and naming conventions for this project except ones given in Code Conventions for the Java Programming Language by Sun. Use best practices and common sense.
  • For code formatting basically Eclipse build-in formatting rules were used with following changes:
    • Indentation → Align fields on columns: on
    • Indentation → Tab policy: Mixed
    • Indentation → Use spaces to indent wrapped lines: on
    • Line Wrapping → Maximum line width: 120
    • Line Wrapping → Default indentation for wrapped lines: 3
    • Comments → Maximum line width for comments: 120
    • Comments → Enable line comment formatting: off
    • New Lines → Insert new line in empty anonymous class body: off
    • New Lines → Insert new line in empty block: off
  • TAB is used for alignment for XML/XSD/... files.

Release procedure

  • Read Sonatype OSS Maven Repository Usage Guide from cover to cover.

  • Use the following settings.xml for your Maven:

      <settings>
      	<!-- Optional proxy configuration (if applicable to your environment) -->
      	<proxies>
      		<proxy>
      			<active>true</active>
      			<protocol>http</protocol>
      			<host>proxy</host>
      			<port>8080</port>
      			<nonProxyHosts>*.internal.domain</nonProxyHosts>
      		</proxy>
      		<proxy>
      			<active>true</active>
      			<protocol>https</protocol>
      			<host>proxy</host>
      			<port>8080</port>
      			<nonProxyHosts>*.internal.domain</nonProxyHosts>
      		</proxy>
      	</proxies>
      
      	<servers>
      		<server>
      			<id>sonatype-nexus-snapshots</id>
      			<username>...sonatype_user...</username>
      			<password>...sonatype_password...</password>
      		</server>
      		<server>
      			<id>sonatype-nexus-staging</id>
      			<username>...sonatype_user...</username>
      			<password>...sonatype_password...</password>
      		</server>
      	</servers>
      
      	<profiles>
      		<profile>
      			<id>gpg</id>
      			<properties>
      				<gpg.passphrase>...passphrase...</gpg.passphrase>
      			</properties>
      		</profile>
      	</profiles>
      </settings>
    
  • Make sure you have git ≥ v1.7.10 installed, otherwise you may face this bug#341221.

  • You need to put JAXB API ≥ v2.2.3 to endorsed directory of JDK which is used to build the project. Otherwise build will fail with java.lang.NoSuchMethodError: javax.xml.bind.annotation.XmlElementWrapper.required()Z.

  • For Hudson freestyle job specify:

Algorithm description

The plugin flow consists of the following parts:

  • Parse arguments.
  • Find classes which are candidates for removal:
    1. The candidate class should not extend any other class (as the total number of properties will be more than 1)
    2. The candidate class should have exactly one non-static property.
    3. This property should be a collection.
    4. This collection should have exactly one parametrisation type.
    5. This parametrisation type should not be java.lang.Object / java.io.Serializable.
  • Visit all classes again to check if the candidate is not eligible for removal:
    1. If there are classes that extend the candidate
    2. If there are class fields that refer the candidate by e.g. @XmlElementRef annotation
  • Visit all classes again to replace the property having the candidate class type with collection plus @XmlElementWrapper annotation. On this step getters/setters are update and ObjectFactory methods are corrected. Also lazy initialization policy is applied.
  • Candidates which are still marked for removal are finally removed (and ObjectFactory is updated accordingly).

There are many pitfalls in JAXB Code Model API which are forcing the developer to use dirty tricks (like accessing private fields) in order to implement the manipulation of code model. Among others:

  • JAXB-784 is about NPE in JAnnotationUse#getAnnotationMembers() method.
  • JAXB-884 is about ClassCastException in JAnnotationArrayMember#annotations() method.
  • JAXB-878 and JAXB-879 describe the lack of public getters for class fields.
  • JAXB-957 mentions what need to be added to make it possible for the inner class to be moved to another class or package.
  • JAXB-883 does not allow to learn if "simpleMode" setting is enabled, which in its turn controls plural form for collection property names. There are however some more difficulties to overcome.

Authors

Original code by Bjarne Hansen. Many thanks to committers:

License

The whole project is licensed under LGPLv3 (or any later version).

jaxb-xew-plugin's People

Contributors

davidfmatheson avatar dmak avatar patrickcrocker avatar sebisteiner avatar wumpz avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.