Skip to content
Alexey Valikov edited this page Aug 31, 2017 · 1 revision

Single property

Single property

Basic single property

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));
    }
Considering XML Schema facets

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 property

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 property

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)));
    }
LOB property

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);
    }
DOM property

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));
    }
Generic ("any"-type) property

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.

Icon 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.

Complex single property
Mapping as many-to-one

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;
    }
Mapping as one-to-one

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;
    }
Mapping as embedded

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>
Mapping as embedded-id

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.

Icon Many thanks to Joachim Björklund for implementing the embedded-id support.

Heterogeneous single property

TODO

Element reference property

TODO

Default mappings for single properties
Default mappings for simple single properties

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>
Clone this wiki locally