-
Notifications
You must be signed in to change notification settings - Fork 99
HyperJAXB3 Reference Single Page
This is a dropin from old and offline highsource's confluence page that may need some adaptation with latest work and may contain links to web.archive.org
Hyperjaxb3 reference is work in progress.
If you already use JAXB, you know how much easier does this great tool make the XML processing in Java. Few lines of code and your XML is turned into an object stucture which is much suitable for Java code than, for instance, DOM or SAX. And you can always turn your object structure back to XML with almoust zero effort.
Generally speaking, there are two principal alternatives for using JAXB in your applications:
- You may start with existing classes and annotate them JAXB annotations.
- You may also start with an XML schema and use the schema compiler (XJC) to compile it into a set of schema-derived classes.
Although the first method is very useful if you want to XMLize existing class hierarchies, the real power of JAXB lies in the second, schema-driven approach. In this case you do not write the code manually - you just provide the XML schema and let JAXB generate the code for you. Schema compiler will analyze the schema and generate the sources of Java classes that represent the XML content.
These classes are called schema-derived classes. They are just normal POJOs (well, almost) and therefore quite easy to handle in Java code. At the same time schema-derived classes contain all the required JAXB annotations (generated by the schema compiler).
Hyperjaxb3 takes you one step further. It makes schema-derived classes persistable with JPA (Java Persistence API), allowing for storing and querying your JAXB objects (instances of schema-derived classes) in a relational database.
Now, if consider JAXB implementing the XML <> objects connection and Hyperjaxb3 providing relational persistence (objects <> RDB), you get the full XML <> objects <> RDB roundtrip.
The goal of Hyperjaxb3 is to provide relational persistence for schema-derived classes. The principal task of Hyperjaxb3 is to turn JAXB schema-derived classes into JPA entity classes so that JPA layer could persist them in a relational database.
In order to achieve this goal, Hyperjaxb3 implements a plugin for JAXB schema compiler which augments modifies or customizes the generated code so that the produced schema-derived classes become valid persistent entity classes.
In order to make schema-derived classes persistable with JPA, Hyperjaxb3 must ensure that they fulfill requirements on the entity class as defined in the JPA specificaltion (see section 2.1). Moreover, to expose generated entities as a persistence unit, Hyperjaxb3 must generate additional files needed for entity packaging (namely the META-INF/persistence.xml
file) as described in the Chapter 6 of the JPA specification.
More specifically, to turn schema-derived classes into JPA entities, Hyperjaxb3 solves the following tasks:
- Generate the
equals(...)
andhashCode()
methods - Applying workarounds for JAXB vs. JPA conflicts
- Adding required properties (for instance, identifier or version properties)
- Generating ORM metadata in form of JPA annotations or XML mapping resources
- Generate the persistence unit descriptor (
META-INF/persistence.xml
)
The following sections of this reference describe how Hyperjaxb3 solves each of these tasks in particular.
Hyperjaxb3 supports standard JPA. Both JPA 1 and JPA 2 (since 0.5.6) are supported.
Hyperjaxb3 is a highly customizable tool. Almost everything Hyperjaxb3 generates can be customized using special customization elements - either directly in schema or in external binding files (*.xjb
).
Customizations are purely optional. You can use them if you want to get certain specific result, but you don't have to if you don't need it. In this case Hyperjaxb3 will apply the default generation strategies.
Please refer to the customization guide for documentation on customizations.
Hyperjaxb3 customizations are very powerful, but still they can not cover all the potential custom cases. However, you can customize Hyperjaxb3 code generation on a deeper level - by writing your own extensions.
Hyperjaxb3 makes heavy use of the strategy pattern. In fact, Hyperjaxb3 is composed from a number of small strategies, each solving its own task. These strategies are configured in a Spring application context. If you want to extend Hyperjaxb3, you can write your own strategy implementations and configure them in the application context (possibly overriding default strategies).
Please refer to the extension guide for more information.
According to the Java Persistence API specification, section 2.1, entities must implement the serializable interface:
If an entity instance is to be passed by value as a detached object (e.g., through a remote interface), the entity class must implement the Serializable interface.
Hyperjaxb2 itself does not enforce serializable classes generation, you should use the jaxb:serializable
global bindings customization element to make your model serializable:
bindings.xjb
<jaxb:bindings version="1.0"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<jaxb:bindings schemaLocation="schema.xsd" node="/xsd:schema">
<jaxb:globalBindings localScoping="toplevel">
<jaxb:serializable/>
</jaxb:globalBindings>
</jaxb:bindings>
</jaxb:bindings>
According to the Java Persistence API specification, section 2.1, entities must be top-level classes:
> The entity class must be a top-level class.Hyperjaxb3 on its own does not (and technically cannot) enforce top-level class generation. You will need to use a JAXB customization to allow this:
schema.xsd
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb">
<xs:annotation>
<xs:appinfo>
<jaxb:globalBindings generateIsSetMethod="true" localScoping="toplevel">
<jaxb:serializable/>
</jaxb:globalBindings>
</xs:appinfo>
</xs:annotation>
<!-- ... -->
</xs:schema>
Although this is not directly required by the JPA specification, it is still recommended to have correct implementations of equals(...)
and hashCode()
methods in entity classes. JAXB uses the equals
and hashCode
plugins from JAXB2 Basics Plugins plugin package to generate these methods.
These plugins generate equals(...)
and hashCode()
methods. With Hyperjaxb3 you can configure, which equals and hash code strategies will be used TODO (default implementations are org.jvnet.jaxb2_commons.lang.JAXBEqualsStrategy
and org.jvnet.jaxb2_commons.lang.JAXBHashCodeStrategy
).
Alternatively you can turn equals(...)
and hashCode()
generation off TODO.
As you might have read in the JAXB vs. JPA document, there is a number of incompatibilities between JAXB and JPA 1. This section explains how Hyperjaxb3 overcomes these incompatibilities.
Hyperjaxb3 supports JPA 2 since version 0.5.6.
Use the jpa2
variant to generate JPA 2 annotations:
Maven:
<plugin>
<groupId>org.jvnet.hyperjaxb3</groupId>
<artifactId>maven-hyperjaxb3-plugin</artifactId>
<configuration>
<variant>jpa2</variant>
</configuration>
</plugin>
Ant:
<xjc destdir="${basedir}/target/generated-sources/xjc" extension="true">
<arg line="
-Xhyperjaxb3-jpa2
-Xhyperjaxb3-jpa2-roundtripTestClassName=RoundtripTest
-Xequals
-Xinheritance
-XhashCode
-XtoString"/>
<binding dir="${basedir}/src/main/resources">
<include name="**/*.xjb"/>
</binding>
<schema dir="${basedir}/src/main/resources">
<include name="**/*.xsd"/>
</schema>
<classpath>
<fileset dir="${basedir}/lib">
<include name="*.jar"/>
</fileset>
</classpath>
</xjc>
Hyperjaxb3 can generate JPA 2 annotations as well as XML mapping files according to the JPA 2 according to the JPA 2 orm_2_0.xsd XML schema. Use mappingFiles or -Xhyperjaxb3-jpa2-result=mappingFiles configuration items accordingly.
JPA 2 supports collections of simple types using the @ElementCollection
annotation.
Hyperjaxb3 uses this feature to improve mapping of the repeatable simple type elements.
Example:
<xsd:complexType name="HJIII-63-Alpha">
<xsd:sequence>
<xsd:element name="stringElements" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="dateElements" type="xsd:date" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
Generates:
@ElementCollection
@OrderColumn(name = "HJINDEX")
@Column(name = "HJVALUE", length = 255)
@CollectionTable(name = "HJIII63ALPHA_STRINGELEMENTS", joinColumns = {
@JoinColumn(name = "HJID")
})
public List<String> getStringElements() { ... }
@ElementCollection
@OrderColumn(name = "HJINDEX")
@Column(name = "HJVALUE", precision = 20, scale = 10)
@CollectionTable(name = "HJIII63ALPHA_DECIMALELEMENTS", joinColumns = {
@JoinColumn(name = "HJID")
})
public List<BigDecimal> getDecimalElements() { ... }
In JPA 2, @Embeddable
mechanism is much more powerful when compared to to JPA 1. Embeddable classes can now have complex properties, associations, collections - and even nested embeddables.
Hyperjaxb3 now supportes @Embeddable
features.
Example:
<xs:element name="unit" type="UnitType"/>
<xs:complexType name="UnitType">
<xs:sequence>
<xs:element name="head" type="PersonType"/>
<xs:element name="address" type="AddressType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="PersonType">
<xs:annotation>
<xs:appinfo>
<hj:embeddable/>
</xs:appinfo>
</xs:annotation>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="address" type="AddressType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="AddressType">
<xs:annotation>
<xs:appinfo>
<hj:embeddable/>
</xs:appinfo>
</xs:annotation>
<xs:sequence>
<xs:element name="street" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="state" type="xs:string" minOccurs="0"/>
<xs:element name="zip" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
</xs:sequence>
</xs:complexType>
Note that both PersonType
as well as AddressType
are embeddable. Moreover, PersonType
has a nested embeddable (address
).
Generates:
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "name", column = @Column(name = "HEAD_NAME", length = 255)),
@AttributeOverride(name = "address.street", column = @Column(name = "HEAD_ADDRESS_STREET", length = 255)),
@AttributeOverride(name = "address.city", column = @Column(name = "HEAD_ADDRESS_CITY", length = 255)),
@AttributeOverride(name = "address.state", column = @Column(name = "HEAD_ADDRESS_STATE", length = 255)),
@AttributeOverride(name = "address.zip", column = @Column(name = "HEAD_ADDRESS_ZIP", length = 255)),
@AttributeOverride(name = "address.country", column = @Column(name = "HEAD_ADDRESS_COUNTRY", length = 255))
})
public PersonType getHead() { ... }
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "street", column = @Column(name = "ADDRESS_STREET", length = 255)),
@AttributeOverride(name = "city", column = @Column(name = "ADDRESS_CITY", length = 255)),
@AttributeOverride(name = "state", column = @Column(name = "ADDRESS_STATE", length = 255)),
@AttributeOverride(name = "zip", column = @Column(name = "ADDRESS_ZIP", length = 255)),
@AttributeOverride(name = "country", column = @Column(name = "ADDRESS_COUNTRY", length = 255))
})
public AddressType getAddress() { ... }
Here's how it looks like in the database:
create table UNITTYPE (
HJID bigint generated by default as identity (start with 1),
ADDRESS_CITY varchar(255),
ADDRESS_COUNTRY varchar(255),
ADDRESS_STATE varchar(255),
ADDRESS_STREET varchar(255),
ADDRESS_ZIP varchar(255),
HEAD_ADDRESS_CITY varchar(255),
HEAD_ADDRESS_COUNTRY varchar(255),
HEAD_ADDRESS_STATE varchar(255),
HEAD_ADDRESS_STREET varchar(255),
HEAD_ADDRESS_ZIP varchar(255),
HEAD_NAME varchar(255), primary key (HJID))
Note that column names for both embeddable AddressType
fields do not collide.
You can mark several properties of your class as identifier properties. In this case these properties will build up a composite primary key. Hyperjaxb3 detects declarations of composite primary keys and automatically generates the required identifier class.
Consider the following schema snippet:
<xsd:complexType name="Parent">
<xsd:sequence>
<xsd:element name="children" type="Child" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="pk1" type="xsd:string">
<xsd:annotation><xsd:appinfo><hj:id /></xsd:appinfo></xsd:annotation>
</xsd:attribute>
<xsd:attribute name="pk2" type="xsd:string">
<xsd:annotation><xsd:appinfo><hj:id /></xsd:appinfo</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="parentData" type="xsd:string"/>
</xsd:complexType>
This type declares two id properties (attributes pk1
and pk2
). To map this composite primary key, HJ3 will generate a ParentId
class:
parent.java
...
@Entity(name = "org.jvnet.hyperjaxb3.ejb.tests.ids.tests.Parent")
@Table(name = "PARENT")
@IdClass(Parent.ParentId.class)
@Inheritance(strategy = InheritanceType.JOINED)
public class Parent implements Equals, HashCode
{
...
@Id
@Column(name = "PK1")
public String getPk1() { ... }
...
@Id
@Column(name = "PK2")
public String getPk2() { ... }
...
public static class ParentId implements Serializable, Equals, HashCode
{
protected String pk1;
protected String pk2;
public String getPk1() { ... }
public void setPk1(String value) { ... }
public String getPk2() { ... }
public void setPk2(String value) { ... }
public boolean equals(Object object) { ... }
public int hashCode() { ... }
}
}
Many thanks to Constantine Kulak who helped with this feature.
Yet to be developed.
Please note that Hyperjaxb3 normalizes and collapses whitespace when generating string fields of annotations. Please see this issue for more information.
By default, Hyperjaxb3 will map schema-derived classes as entities.
Schema fragment:
<xsd:complexType name="PurchaseOrderType">
<xsd:sequence>
<xsd:element name="shipTo" type="USAddress"/>
<xsd:element name="billTo" type="USAddress"/>
<xsd:element ref="comment" minOccurs="0"/>
<xsd:element name="items" type="Items"/>
</xsd:sequence>
<xsd:attribute name="orderDate" type="xsd:date"/>
</xsd:complexType>
Produces:
@Entity(name = "PurchaseOrderType")
@Table(name = "PURCHASEORDERTYPE")
@Inheritance(strategy = InheritanceType.JOINED)
public class PurchaseOrderType
implements Equals, HashCode
{ ... }
Entity name is typically the local name of the class and table name is derived from the class name. You can customize both (and much more) using the customization element hj:entity
:
<jaxb:bindings node="xs:complexType[@name='PurchaseOrderType']">
<hj:entity name="PO">
<orm:table name="PO"/>
</hj:entity>
</jaxb:bindings>
Produces:
@Entity(name = "PO")
@Table(name = "PO")
@Inheritance(strategy = InheritanceType.JOINED)
public class PurchaseOrderType
implements Equals, HashCode
{ ... }
For better compatibility, entity names should not contain dots. Prior to version 0.5.5 HJ3 used fully qualified class names as entity names. It worked fine with Hibernate but caused problems in other persistence providers.
TODO
JPA provides support for embeddable classes which represent entity state but do not have persistent identity of their own. You may instruct Hyperjaxb3 to map your schema-derived class as embeddable class by using the hj:embeddable
customization element:
<xs:complexType name="PrimaryPhoneType">
<xs:annotation>
<xs:appinfo>
<hj:embeddable/>
</xs:appinfo>
</xs:annotation>
<xs:sequence>
<xs:element name="phoneNumber" type="xs:string" nillable="false"/>
<xs:element name="phoneType" type="xs:string" nillable="false"/>
</xs:sequence>
</xs:complexType>
JPA poses strict limitations on embeddable classes. In particular, only simple properties are allowed in embeddable classes. If your embeddable class has properties which are not supported in JPA, they will be made transient automatically.
In order to avoid name collisions, Hyperjaxb3 by default generates the attribute-override
definitions and provides syntetic column names:
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "phoneNumber", column = @Column(name = "PRIMARYPHONEITEM_PHONENUMBER")),
@AttributeOverride(name = "phoneType", column = @Column(name = "PRIMARYPHONEITEM_PHONETYPE"))
})
public PrimaryPhoneType getPrimaryPhoneItem() { ... }
Single property which references an embeddable class will can be mapped as embedded
(default) or embedded-id
.
If you don't want to map a certain class, you can annotate it with <hj:ignored/>
:
<xs:complexType name="MyType">
<xs:annotation>
<xs:appinfo>
<hj:ignored/>
</xs:appinfo>
</xs:annotation>
<!-- ... -->
</xs:complexType>
Since 0.5.5.
In certain cases you may want to exclude whole packages from mapping. Here's how to do it:
schema-ignored.xsd
<xsd:schema ...
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:hj="http://hyperjaxb3.jvnet.org/ejb/schemas/customizations"
jaxb:extensionBindingPrefixes="hj">
<xsd:annotation>
<xsd:appinfo>
<jaxb:schemaBindings>
<jaxb:package name="org.jvnet.hyperjaxb3.ejb.tests.issuesignored"/>
</jaxb:schemaBindings>
<hj:ignored-package name="org.jvnet.hyperjaxb3.ejb.tests.issuesignored"/>
</xsd:appinfo>
</xsd:annotation>
<!-- ... -->
</xsd:schema>
You can do the same in bindings file:
<!-- ... -->
<jaxb:bindings schemaLocation="schema-ignored.xsd" node="/xsd:schema">
<jaxb:schemaBindings>
<jaxb:package name="org.jvnet.hyperjaxb3.ejb.tests.issuesignored"/>
</jaxb:schemaBindings>
<hj:ignored-package name="org.jvnet.hyperjaxb3.ejb.tests.issuesignored"/>
</jaxb:bindings>
<!-- ... -->
Due to certain techical limitations you need to specify the package name in hj:ignored-package/@name
.
JPA requires entities to have primary keys. To satisfy this requirement, you can select an identifier property using a customization or let Hyperjaxb3 generate an identifier property for you. Below is the identifier property which will be generated by default:
@XmlAttribute(name = "Hjid")
protected Long hjid;
@Id
@Column(name = "HJID")
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getHjid() {
return hjid;
}
public void setHjid(Long value) {
this.hjid = value;
}
You still can customize the identifier property generated for a certain entity or even by default for all entities.
Version properties are optional in JPA, but they are very useful for handling optimistic locking. You can select one of your properties as the version property using the customization. If you don't have a suitable property, you may also customize Hyperjaxb3 to generate a version property for you:
<xsd:complexType name="MyType">
<xsd:annotation>
<xsd:appinfo>
<hj:generated-version/>
</xsd:appinfo>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
Here's what will be generated:
@Version
@Column(name = "HJVERSION")
public Long getHjversion() {
return hjversion;
}
public void setHjversion(Long value) {
this.hjversion = value;
}
You can customize the version property generated for a certain entity or by default for all entities.
Simple-typed single properties are mapped as @Basic
properties:
<xs:complexType name="simpleTypesType">
<xs:sequence>
<xs:element name="string" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
protected String string;
@Basic
@Column(name = "STRING", length = 255)
public String getString() {
return string;
}
public void setString(String value) {
this.string = value;
}
If Java type of the simple property is not supported by JPA, such properties will be wrapped:
<xs:element name="duration" type="xs:duration" minOccurs="0"/>
protected Duration duration;
@Transient
public Duration getDuration() {
return duration;
}
public void setDuration(Duration value) {
this.duration = value;
}
@Basic
@Column(name = "DURATIONITEM", length = 127)
public String getDurationItem() {
return XmlAdapterUtils.unmarshall(DurationAsString.class, this.getDuration());
}
public void setDurationItem(String target) {
setDuration(XmlAdapterUtils.marshall(DurationAsString.class, target));
}
Hyperjaxb3 considers XML Schema facets when generating length, scale and precision:
<xsd:simpleType name="digits">
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="5"/>
<xsd:fractionDigits value="2"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType ...>
<xsd:sequence>
<xsd:element name="digits" minOccurs="0" type="test:digits"/>
</xsd:sequence>
</xsd:complexType>
protected BigDecimal digits;
@Basic
@Column(name = "DIGITS", precision = 5, scale = 2)
public BigDecimal getDigits() {
return digits;
}
public void setDigits(BigDecimal value) {
this.digits = value;
}
Hyperjaxb3 considers the following facets:
xsd:minLength
xsd:maxLength
xsd:length
xsd:totalDigits
xsd:fractionDigits
Temporal properties (typed xsd:dateTime
, xsd:date
, xsd:time
and so on) will be mapped as temporal JPA properties. Hyperjaxb3 will choose temporal type as TIMESTAMP
, DATE
or TIME
depending on the XML Schema type of the temporal property.
Temporal properties are typically mapped onto XMLGregorianCalendar
which is not supported by JPA - and therefor must be wrapped:
<xs:element name="dateTime" type="xs:dateTime" minOccurs="0"/>
@XmlSchemaType(name = "dateTime")
protected XMLGregorianCalendar dateTime;
@Transient
public XMLGregorianCalendar getDateTime() {
return dateTime;
}
public void setDateTime(XMLGregorianCalendar value) {
this.dateTime = value;
}
@Basic
@Column(name = "DATETIMEITEM")
@Temporal(TemporalType.TIMESTAMP)
public Date getDateTimeItem() {
return XmlAdapterUtils.unmarshall(XMLGregorianCalendarAsDateTime.class, this.getDateTime());
}
public void setDateTimeItem(Date target) {
setDateTime(XmlAdapterUtils.marshall(XMLGregorianCalendarAsDateTime.class, target));
}
Enumerated properties are typically mapped as enumerated JPA properties:
<xsd:simpleType name="SexType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="Male"/>
<xsd:enumeration value="Female"/>
</xsd:restriction>
</xsd:simpleType>
...
<xsd:element name="sex" type="test:SexType"/>
...
@XmlElement
protected SexType sex;
@Basic
@Column(name = "SEX")
@Enumerated(EnumType.STRING)
public SexType getSex() {
return sex;
}
public void setSex(SexType value) {
this.sex = value;
}
You can also map the enumerated property as value (instead of enumeration):
<xsd:element name="sex" type="test:SexType">
<xsd:annotation>
<xsd:appinfo>
<hj:basic>
<hj:enumerated-value/>
</hj:basic>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
@XmlElement(required = true)
protected SexType sex;
@Transient
public SexType getSex() {
return sex;
}
public void setSex(SexType value) {
this.sex = value;
}
@Basic
@Column(name = "SEXITEM")
public String getSexItem() {
return ((this.getSex() == null)?null:this.getSex().value());
}
public void setSexItem(String target) {
setSex(((target == null)?null:SexType.fromValue(target)));
}
Binary properties (xsd:hexBinary
, xsd:base64Binary
) will be mapped as LOB properties:
<xs:element name="base64Binary" type="xs:base64Binary" minOccurs="0"/>
protected byte[] base64Binary;
@Basic
@Column(name = "BASE64BINARY")
@Lob
public byte[] getBase64Binary() {
return base64Binary;
}
public void setBase64Binary(byte[] value) {
this.base64Binary = ((byte[]) value);
}
Generic properties represented in the Java model by DOM elements will be wrapped and mapped as String (XML representation of the DOM element):
<xsd:complexType ...>
<xsd:sequence>
<xsd:any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
@XmlAnyElement
protected Element any;
@Transient
public Element getAny() {
return any;
}
public void setAny(Element value) {
this.any = value;
}
@Basic
@Column(name = "ANYITEM")
@Lob
public String getAnyItem() {
return XmlAdapterUtils.unmarshall(ElementAsString.class, this.getAny());
}
public void setAnyItem(String target) {
setAny(XmlAdapterUtils.marshall(ElementAsString.class, target));
}
A further JAXB feature is generic or any-type properties like those generated from xsd:anyType
-typed elements or xsd:any
with strict processing:
<xsd:any namespace="##other" processContents="strict" minOccurs="0" maxOccurs="1"/>
Turns into:
@XmlAnyElement(lax = true)
protected Object any;
public Object getAny() {
return any;
}
public void setAny(Object value) {
this.any = value;
}
JPA can't handle these generic properties. Hyperjaxb3's approach to handle this scenario is to adapt the property by marshalling its contents into string in getter and unmarshalling the string in setter. By default, Hyperjaxb3 uses the context path of the currently processed schema (or schemas).
public final static String AnyObjectContextPath = "org.jvnet.hyperjaxb3.ejb.tests.any";
@Basic
@Column(name = "AnyObject")
public String getAnyObject() {
if (JAXBContextUtils.isMarshallable(AnyObjectContextPath , this.getAny())) {
return JAXBContextUtils.marshal(AnyObjectContextPath , this.getAny());
} else {
return null;
}
}
public void setAnyObject(String target) {
if (target!= null) {
setAny(JAXBContextUtils.unmarshal(AnyObjectContextPath , target));
}
}
The approach presented above is quite similar to the way how the DOM elements are processed. The only difference is that instead of using XML parsing and serialization, contents of the property are marshalled/unmarshalled with JAXB context.
You can use the hj:generated-property customization element to customize the generated property or hj:jaxb-context to customize the path of the JAXB context used for marshalling/unmarshalling.
By default complex single properties are mapped as @ManyToOne
:
<xs:element name="single" type="complexType" minOccurs="0"/>
protected ComplexType single;
@ManyToOne(targetEntity = ComplexType.class, cascade = {
CascadeType.ALL
})
@JoinColumn(name = "SINGLE_COMPLEXTYPESTYPE_HJID")
public ComplexType getSingle() {
return single;
}
public void setSingle(ComplexType value) {
this.single = value;
}
You can use the hj:one-to-one
customization element to map your complex single property as @OneToOne
instead of @ManyToOne
:
<xs:element name="one-to-one-join-column" type="test:three" minOccurs="0">
<xs:annotation>
<xs:appinfo>
<hj:one-to-one>
<orm:join-column name="O2OJC_THREE_ID"/>
</hj:one-to-one>
</xs:appinfo>
</xs:annotation>
</xs:element>
@XmlElement(name = "one-to-one-join-column")
protected Three oneToOneJoinColumn;
@OneToOne(targetEntity = Three.class, cascade = {
CascadeType.ALL
})
@JoinColumn(name = "O2OJC_THREE_ID")
public Three getOneToOneJoinColumn() {
return oneToOneJoinColumn;
}
public void setOneToOneJoinColumn(Three value) {
this.oneToOneJoinColumn = value;
}
If the target class is made embeddable, the complex single property can be mapped either as embedded
or as embedded-id
property.
Consider the following example:
<xs:complexType name="PrimaryPhoneType">
<xs:annotation>
<xs:appinfo>
<hj:embeddable/>
</xs:appinfo>
</xs:annotation>
<xs:sequence>
<xs:element name="phoneNumber" type="xs:string" nillable="false"/>
<xs:element name="phoneType" type="xs:string" nillable="false"/>
</xs:sequence>
</xs:complexType>
By default, complex single properties referencing the PrimaryPhoneType
will be automatically turned mapped as embedded
. You can further customize this mapping using hj:embedded
customization element. For instance, you can specify orm::attribute-override
elements to override column mappings:
<xs:complexType name="EmployeeType">
<xs:sequence>
<!-- ... -->
<xs:element name="primaryPhone" nillable="true" minOccurs="0" type="PrimaryPhoneType">
<xs:annotation>
<xs:appinfo>
<hj:embedded>
<orm:attribute-override name="phoneNumber">
<orm:column name="phone_no"/>
</orm:attribute-override>
<orm:attribute-override name="phoneType">
<orm:column name="phone_type_id"/>
</orm:attribute-override>
</hj:embedded>
</xs:appinfo>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
Alternatively, you can map a complex single property which references an embeddable class as embedded-id
. This is not a default mapping, you have to use the hj:embedded-id
customization element to enable this:
<xs:complexType name="embeddableIdType">
<xs:annotation>
<xs:appinfo>
<hj:embeddable/>
</xs:appinfo>
</xs:annotation>
<xs:sequence>
<xs:element name="id1" type="xs:long" minOccurs="0"/>
<xs:element name="id2" type="xs:long" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="entityWithEmbeddedIdType">
<xs:sequence>
<xs:element name="id" type="embeddableIdType">
<xs:annotation>
<xs:appinfo>
<hj:embedded-id/>
</xs:appinfo>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
This will instruct HJ3 to generate an embedded-id
property:
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = "id1", column = @Column(name = "ID_ID1")),
@AttributeOverride(name = "id2", column = @Column(name = "ID_ID2"))
})
public EmbeddableIdType getId() { ... }
Accordingly, no further identifier properties will be generated in this case.
Many thanks to Joachim Björklund for implementing the embedded-id support.
TODO
TODO
Default mappings for simple properties are defined on the per-type basis in default customizations. These mappings are developed based on the XML Schema type hierarchy :
Below is the table describing default mappings for XML Schema build-in types:
# |
Type |
Mapping |
---|---|---|
3.2.1 |
xsd:string |
<hj:basic><orm:column length="255"/></hj:basic> |
3.2.3 |
xsd:decimal |
<hj:basic><orm:column scale="10" precision="20"/></hj:basic> |
3.2.4 |
xsd:float |
<hj:basic><orm:column scale="10" precision="20"/></hj:basic> |
3.2.5 |
xsd:double |
<hj:basic><orm:column scale="10" precision="20"/></hj:basic> |
3.2.6 |
xsd:duration |
<hj:basic><orm:column length="127"/></hj:basic> |
3.2.7 |
xsd:dateTime |
<hj:basic><orm:temporal>TIMESTAMP</orm:temporal></hj:basic> |
3.2.8 |
xsd:time |
<hj:basic><orm:temporal>TIME</orm:temporal></hj:basic> |
3.2.9 |
xsd:date |
<hj:basic><orm:temporal>DATE</orm:temporal></hj:basic> |
3.2.10 |
xsd:gYearMonth |
<hj:basic><orm:temporal>DATE</orm:temporal></hj:basic> |
3.2.11 |
xsd:gYear |
<hj:basic><orm:temporal>DATE</orm:temporal></hj:basic> |
3.2.12 |
xsd:gMonthDay |
<hj:basic><orm:temporal>DATE</orm:temporal></hj:basic> |
3.2.13 |
xsd:gDay |
<hj:basic><orm:temporal>DATE</orm:temporal></hj:basic> |
3.2.14 |
xsd:gMonth |
<hj:basic><orm:temporal>DATE</orm:temporal></hj:basic> |
3.2.15 |
xsd:hexBinary |
<hj:basic><<orm:lob/></hj:basic> |
3.2.16 |
xsd:base64Binary |
<hj:basic><orm:lob/></hj:basic> |
3.3.3 |
xsd:language |
<hj:basic><orm:column length="17"/></hj:basic> |
3.3.13 |
xsd:integer |
<hj:basic><orm:column scale="0" precision="20"/></hj:basic> |
3.3.16 |
xsd:long |
<hj:basic><orm:column scale="0" precision="20"/></hj:basic> |
3.3.17 |
xsd:int |
<hj:basic><orm:column scale="0" precision="10"/></hj:basic> |
3.3.18 |
xsd:short |
<hj:basic><orm:column scale="0" precision="5"/></hj:basic> |
3.3.19 |
xsd:byte |
<hj:basic><orm:column scale="0" precision="3"/></hj:basic> |
3.3.21 |
xsd:unsignedLong |
<hj:basic><orm:column scale="0" precision="20"/></hj:basic> |
3.3.22 |
xsd:unsignedInt |
<hj:basic><orm:column scale="0" precision="10"/></hj:basic> |
3.3.23 |
xsd:unsignedShort |
<hj:basic><orm:column scale="0" precision="5"/></hj:basic> |
3.3.24 |
xsd:unsignedByte |
<hj:basic><orm:column scale="0" precision="3"/></hj:basic> |
According to the entity packaging guidelines of the JPA specification, Hyperjaxb3 generates the META-INF/persistence.xml
file which describes generated classes in a persistence unit. This allows easier usage of mapped classes - entity manager will pick up the classes automatically.
Hyperjaxb3 generates the persistence unit in the META-INF/persistence.xml
file in the target directory. You may configure an alternative location TODO if you wish.
Persistence unit generated by Hyperjaxb3 simply lists classes which were made entities:
META-INF/persistence.xml
<persistence
version="1.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="org.jvnet.hyperjaxb3.ejb.tests.po">
<class>org.jvnet.hyperjaxb3.ejb.tests.po.Items</class>
<class>org.jvnet.hyperjaxb3.ejb.tests.po.Items$Item</class>
<class>org.jvnet.hyperjaxb3.ejb.tests.po.USAddress</class>
<class>org.jvnet.hyperjaxb3.ejb.tests.po.PurchaseOrderType</class>
</persistence-unit>
</persistence>
Persistence unit in named after the package of the schema-derived classes. If there are several packages, they'll be colon-separated (just lice JAXB context path). You may also specify the name of the persistence unit expliciltly in configuration.
You may also turn off the generation of persistence.xml TODO.
One of the ways to create a custom persistence unit descriptor is letting HJ3 inject its definitions into an existing persistence.xml
template. To do this, you have to set the persistenceXml
configuration element in Ant or Maven. Below is an example for Maven:
<plugin>
<groupId>org.jvnet.hyperjaxb3</groupId>
<artifactId>maven-hyperjaxb3-plugin</artifactId>
<configuration>
<persistenceXml>src/main/etc/persistence.xml</persistenceXml>
</configuration>
</plugin>
The persistenceXml
configuration element should point to the persistence.xml
template:
src/main/etc/persistence.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence version="1.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="##generated" transaction-type="RESOURCE_LOCAL">
<mapping-file>org/jvnet/hyperjaxb3/ejb/tests/po/orm.xml</mapping-file>
</persistence-unit>
</persistence>
In this case HJ3 will not create the persistence.xml
file from scratch, instead it will parse the provided template and inject its definitions (class
or mapping-file
elements) into the right places:
target/generated-sources/xjc/META-INF/persistence.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence version="1.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd
http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
xmlns:orm="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="org.jvnet.hyperjaxb3.ejb.tests.po" transaction-type="RESOURCE_LOCAL">
<mapping-file>org/jvnet/hyperjaxb3/ejb/tests/po/orm.xml</mapping-file>
<class>org.jvnet.hyperjaxb3.ejb.tests.po.Items</class>
<class>org.jvnet.hyperjaxb3.ejb.tests.po.Items$Item</class>
<class>org.jvnet.hyperjaxb3.ejb.tests.po.PurchaseOrderType</class>
<class>org.jvnet.hyperjaxb3.ejb.tests.po.USAddress</class>
</persistence-unit>
</persistence>
When building the project, you may also want to generate a database schema (DDL) for the persistence unit which was created by the Hyperjaxb3. This is done differently depending in your build tool and the persistence provider you use. The following sections illustrate some of the setups.
Hibernate includes the Hibernate Tools sub-project which provides the hbm2ddl
database schema exporter.
The easiest way of integrating hbm2ddl
in your Maven builds is the Hibernate3 Maven Plugin. Here's a sample configuration:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>hibernate3-maven-plugin</artifactId>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>hbm2ddl</goal>
</goals>
</execution>
</executions>
<configuration>
<components>
<component>
<name>hbm2ddl</name>
<implementation>jpaconfiguration</implementation>
<outputDirectory>target/generated-resources/hbm2ddl</outputDirectory>
</component>
</components>
<componentProperties>
<!-- Name of the persistence unit -->
<persistenceunit>com.acme.foo</persistenceunit>
<!-- Hibernate properties -->
<propertyfile>src/test/resources/persistence.properties</propertyfile>
<outputfilename>schema.ddl</outputfilename>
<drop>false</drop>
<create>true</create>
<export>false</export>
<format>true</format>
</componentProperties>
</configuration>
</plugin>
It is important that this plugin is invoked, after the compile
phase (for instance, in the process-classes
phase) since it needs the compiled classes for schema generation.
Hibernate properties file must at least provide the dialect:
persistence.properties
hibernate.dialect=org.hibernate.dialect.HSQLDialect
Apache CXF is an open source services framework. CXF helps you build and develop services using frontend programming APIs, like JAX-WS and JAX-RS. These services can speak a variety of protocols such as SOAP, XML/HTTP, RESTful HTTP, or CORBA and work over a variety of transports such as HTTP, JMS or JBI.
One of the features of Apache CXF is WSDL-to-Java code generation with the cxf-codegen-plugin for Maven. You can invoke Hyperjaxb3 from this plugin to turn some of the WSDL- or schema-derived classes JPA-conform.
Since 0.5.5.
The cxf-codegen-plugin
uses JAXB schema compiler (XJC) internally. This gives the possibility to invoke Hyperjaxb3 as a normal XJC plugin. To achieve this, you need to do the following:
- Add JAXB2 Basics and Hyperjaxb3 EJB Plugin to the dependencies of
cxf-codegen-plugin
. - Activate
equals
,hashCode
andhyperjaxb3-ejb
plugins using theextraargs/extraarg
configuration elements.
Here's an example of the cxf-codegeb-plugin
configuration:
A fragment of pom.xml
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
<configuration>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/src/main/wsdl/myService.wsdl</wsdl>
<bindingFiles>
<!-- JAX-WS bindings -->
<bindingFile>${basedir}/src/main/wsdl/binding.xml</bindingFile>
<!-- XJC bindings -->
<bindingFile>${basedir}/src/main/wsdl/binding.xjb</bindingFile>
</bindingFiles>
<extraargs>
<!-- Turns on the hashCode plugin -->
<extraarg>-xjc-XhashCode</extraarg>
<!-- Turns on the equals plugin -->
<extraarg>-xjc-Xequals</extraarg>
<!-- Turns on the Hyperjaxb3 EJB plugin -->
<extraarg>-xjc-Xhyperjaxb3-ejb</extraarg>
</extraargs>
</wsdlOption>
</wsdlOptions>
</configuration>
<dependencies>
<dependency>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics</artifactId>
<version><!-- version --></version>
</dependency>
<dependency>
<groupId>org.jvnet.hyperjaxb3</groupId>
<artifactId>hyperjaxb3-ejb-plugin</artifactId>
<version><!-- version --></version>
</dependency>
</dependencies>
</plugin>
See this tutorial for an example.
Hyperjaxb3 does not generate any vendor-specific annotations or mappings, only standard JPA. The main reason for this is that vendor-specific support is extremely effort-consuming, I can't handle such efforts in the frame of a non-commercial product.
If you have a high-profile project which need vendor-specific extensions and ready to invest in development, you may get in contact with me.
Having stated that, there is still a solution which allows you adding vendor-specific annotations to the generated classes. This solution is based on the Annotate Plugin which I've developed in the frame of the JAXB2 Basics project.
Here's a short overview of this solution:
- Include the annotation library into your classpath.
- Enable the Annotate plugin in your build.
- Add
annox:annotate
customization elements.
Basically, you let Hyperjaxb3 generate standard JPA annotations and add non-standard (verndor-specific) things via customizations.
I'll demonstrate it by the example of Hibernate Annotations.
Assume we want to add a DELETE_ORPHAN
cascade to the one-to-many property:
@OneToMany(targetEntity = Foo.class, cascade = {
javax.persistence.CascadeType.ALL
})
@org.hibernate.annotations.Cascade({
org.hibernate.annotations.CascadeType.DELETE_ORPHAN
})
public List<Foo> getFoos() {...}
The @OneToMany
is a standard JPA annotation which is generated by Hyperjaxb3. However @org.hibernate.annotations.Cascade
is Hibernate-specific annotation which is not handled by Hyperjaxb3. We'll need the Annotate Plugin for this.
First of all you must make the annotation library (Hibernate Annotations in this case) available by adding it to the dependencies of the maven-hyperjaxb3-plugin
:
<plugin>
<groupId>org.jvnet.hyperjaxb3</groupId>
<artifactId>maven-hyperjaxb3-plugin</artifactId>
<configuration>
...
</configuration>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.4.0.GA</version>
</dependency>
</dependencies>
</plugin>
Next we'll need to turn on the Annotate plugin:
<plugin>
<groupId>org.jvnet.hyperjaxb3</groupId>
<artifactId>maven-hyperjaxb3-plugin</artifactId>
<configuration>
...
<args>
<arg>-Xannotate</arg>
</args>
</configuration>
<dependencies>...</dependencies>
</plugin>
Now we're ready to customize:
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:hj="http://hyperjaxb3.jvnet.org/ejb/schemas/customizations"
xmlns:orm="http://java.sun.com/xml/ns/persistence/orm"
xmlns:annox="http://annox.dev.java.net"
xmlns:ha="http://annox.dev.java.net/org.hibernate.annotations"
jaxb:extensionBindingPrefixes="hj orm xjc annox"
jaxb:version="2.1" ... >
<!-- ... -->
<xs:complexType name="...">
<xs:sequence>
<xs:element name="foo" type="test:foo" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:appinfo>
<annox:annotate>
<ha:Cascade value="DELETE_ORPHAN"/>
</annox:annotate>
</xs:appinfo>
</xs:annotation>
</xs:element>
<!-- ... -->
</xs:sequence>
</xs:complexType>
<!-- ... -->
</xs:schema>
Please see the Annotate Plugin documentation and Annox User Guide for more information on formulation your Java annotations in XML.
See the cu-one test project for the working example.
- Home
- Migration guide
-
JAXB Maven Plugin
- Quick Start
-
User Guide
- Basic Usage
- Specifying What To Compile
- Referencing Resources in Maven Artifacts
- Using Catalogs
- Using Episodes
- Modular Schema Compilation
- Controlling the Output
- Using JAXB Plugins
- Using a Specific JAXB Version
- Configuring Extension, Validation and XML Security
- IDE Integration
- Miscellaneous
- Configuring Proxies
- Maven Documentation
- Configuration Cheat Sheet
- Common Pitfalls and Problems
-
JAXB2 Basics Plugins
- Using JAXB2 Basics Plugins
- JSR-305 Support
-
JAXB2 Basics Plugins List
- SimpleEquals Plugin
- SimpleHashCode Plugin
- Equals Plugin
- HashCode Plugin
- ToString Plugin
- Copyable Plugin
- Mergeable Plugin
- Inheritance Plugin
- AutoInheritance Plugin
- Wildcard Plugin
- Setters Plugin
- Simplify Plugin
- EnumValue Plugin
- JAXBIndex Plugin
- FixJAXB1058 Plugin
- Commons Lang Plugin
- Default Value Plugin
- Fluent API Plugin
- Namespace Prefix Plugin
- Value Constructor Plugin
- Boolean Getter Plugin
- CamelCase Plugin
- XML ElementWrapper Plugin
- Parent Pointer Plugin
- Property Listener Injector Plugin
- Annox
- JAXB Annotate Plugin
-
HyperJAXB3
- Build System Support
- Customization Guide
- Databases
- Development guide
- Extension guide
- FAQ
- IDE Support
- Java Persistence
- JAXB
- JDK Support
- Project Templates
-
Reference
- Adding vendor-specific annotations
- Features
- Integrating Hyperjaxb3 in builds
- Introduction
- Making schema-derived classes ready for JPA
- Adding required properties
- Applying workarounds for JAXB vs. JPA conflicts
- Enforcing top-level classes
- Generating equals and hashCode methods
- Generating ORM metadata
- Generating persistence unit descriptor
- JPA 2 Support
- Making classes serializable
- Testing generated mappings
- Reference - single page
- Related Projects
- Sample projects
- Solutions
- Target Scenarios
- Test Projects
- Tutorials
- Best Practices
- FAQ
- Sample Projects
- Support
- License
- Distribution