-
Notifications
You must be signed in to change notification settings - Fork 99
HyperJAXB3 JAXB vs. JPA
Both JAXB and JPA work with Java objects. JAXB provides objects with XML binding, JPA - with relational persistence. Unfortunatelly, combining these two technologies is complicated by the fact that there is a number of severe incompatibilities between them. These incompatibilities are mainly due to the limitations of JPA specifications. However, there are also few JAXB-specific issues.
In this section I'll explain major JAXB/JPA incompatibilities and sketch out solutions implemented in Hyperjaxb3.
JPA only supports the following property types:
- primitive types, wrappers of the primitive types;
-
java.lang.String
; -
java.math.BigInteger
,java.math.BigDecimal
; -
java.util.Date
,java.util.Calendar
,java.sql.Date
,java.sql.Time
,java.sql.Timestamp
- serializable types;
-
byte[]
,Byte[]
,char[]
,Character[]
; - enums;
- entity types;
- collections of entity types;
- embeddable classes.
As you see, this set is quite limited. Only a very small number of simple types is supported. Take, for instance a good old java.net.URL
- it will be mapped as a serializiable type (so say goodbye to the nice string representation of the URL). JPA also does not provide any way to define own custom types (like "user-defined types" in Hibernate).
JAXB in its turn does use some simple types which are not supported by JPA, for instance:
-
javax.xml.namespace.QName
(xsd:QName
), -
javax.xml.datatype.Duration
(xsd:duration
), -
javax.xml.datatype.XMLGregorianCalendar
(xsd:date
,xsd:time
,xsd:dateTime
,xsd:gYearMonth
,xsd:gYear
,xsd:gMonthDay
,xsd:gDay
,xsd:gMonth
).
Sometimes it is also desired to map a list of strings as a comma-separated strings, not as a collection
In order to allow these "custom" simple types to be mapped by JPA, Hyperjaxb3 adds another getter/setter pair which adapt the problematic property and perform conversion when accessed.
As the JPA spec excerpt above says, JPA supports collections of entity types only. So if you have a list of number or a set of strings, you can't map it with JPA. Not too POJO-friendly, I would say.
At the same time, JAXB generates collections of simple types quite naturally. For instance the following element:
<xs:element name="myLongCollection" type="xs:long" minOccurs="0" maxOccurs="unbounded"/>
This will quite naturally produce the following property:
public List<Long> getLong() {
if (_long == null) {
_long = new ArrayList<Long>();
}
return this._long;
}
This property is not mappable with pure JPA. To overcome this, Hyperjaxb3 creates a new artificial entity and wrapes the simple collection as a collection of entities.
Depending on typing, collections may be homogeneous (all elements have the same common base type) or heterogeneous (elements have different types). Heterogeneous collections are not quite common in the POJO world, depelopers usually prefer homogeneous collections.
There are certain cases, when JAXB generates heterogeneous collection properties. For instance, if you have a repetable sequence in your schema, it's likely that you'll get a heterogeneous collection. Consider the following example:
<xs:complexType name="heteroSequenceType">
<xs:sequence>
<!-- ... -->
<xs:sequence maxOccurs="unbounded">
<xs:element name="e" type="xs:string"/>
<xs:element name="f" type="complexType"/>
</xs:sequence>
<!-- ... -->
</xs:sequence>
</xs:complexType>
/**
* Gets the value of the eAndF property.
* ...
* Objects of the following type(s) are allowed in the list
* {@link String }
* {@link ComplexType }
*/
@Transient
public List<Object> getEAndF() {
if (eAndF == null) {
eAndF = new ArrayList<Object>();
}
return this.eAndF;
}
The EAndF
property is a heterogeneous list - it can contain strings as well as instances of ComplexType
as well.
JPA can't map this type of collections. Therefore Hyperjaxb3 needs to "homogenize" the collection by introducing a new artificial entity capable of holding all the possible collection types - and adapting the heterogeneous collection property with a new homogenized collection.
This is probably the most complicated hack carried out by Hyperjaxb3.
In certain cases JAXB generates properties where the real value is wrapped into javax.xml.bind.JAXBElement
. For instance, if you declare a nillable element, JAXB will wrap the actual value:
<xs:element name="dateNillable" type="xs:date" minOccurs="0" nillable="true"/>
public JAXBElement<XMLGregorianCalendar> getDateNillable() {
return dateNillable;
}
Needless to say, this type of properties can't be mapped by JPA. They have to be wrapped into collections of simplifies types.
A very useful extension of JAXB is xjc:dom
which instructs JAXB to load a part of the XML document into an object structure as a DOM element - without any unmarshalling:
<xs:element name="single" minOccurs="0">
<xs:annotation>
<xs:appinfo>
<xjc:dom/>
</xs:appinfo>
</xs:annotation>
</xs:element>
@XmlAnyElement
protected Element single;
public Element getSingle() {
return single;
}
DOM elements can't be persisted by JPA. Hyperjaxb3 solves this problem by converting the DOM into XML string in the wrapping property.
JAXB is capable of handling XML Schema's xsd:any
constructs. Depending on the processing type (strict
, lax
, skip
) you may get DOM properties (skip
procesing), generic properties (strict
) or even mixed properties. Generic properties may contain any object type available in current JAXB context. This contradicts JPA where you have to know the type of the associated entity.
To handle this case, Hyperjaxb3 marshalls the generic content and saves it as string.
- 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