HHH-9998 - Continue documentation TLC - mapping basic-types

This commit is contained in:
Steve Ebersole 2015-08-02 14:07:26 -05:00
parent 84987f46b7
commit 4f725332af
31 changed files with 911 additions and 61 deletions

View File

@ -34,8 +34,8 @@
<para>
This chapter will describe the characteristics of a persistable domain model. However, it will not discuss
defining the mapping for the domain model. That is a massive topic in its own right and is the subject of an
entire dedicated manual. See the <citetitle>Hibernate - Domain Model Mapping</citetitle> documentation
from the <link xlink:href="http://hibernate.org/documentation">documentation site</link>.
entire dedicated manual. See the <citetitle>Hibernate Domain Model Mapping Guide</citetitle> from the
<link xlink:href="http://hibernate.org/documentation">documentation site</link>.
</para>
<section xml:id="domainmodel-pojo">

View File

@ -48,17 +48,26 @@
<xi:include href="chapters/basic/Basic_Types.xml" />
<xi:include href="chapters/composition/Composition.xml" />
<xi:include href="chapters/collection/Collection.xml" />
<xi:include href="chapters/entity/Entity.xml" />
<xi:include href="chapters/id/Identifiers.xml" />
<xi:include href="chapters/natural_id/Natural_Id.xml" />
<!--
<xi:include href="chapters/entity/Entity.xml" />
<xi:include href="chapters/id/Identifiers.xml" />
<xi:include href="chapters/association/Associations.xml" />
<xi:include href="chapters/natural_id/Natural_Id.xml" />
<xi:include href="chapters/secondary/Secondary_Tables.xml" />
<xi:include href="chapters/constraints/Database_Constraints.xml" /> pk, fk, index, check, unique
<xi:include href="chapters/auxiliary/Auxiliary_DB_Objects.xml" />
<xi:include href="chapters/generation/Generated_attributes.xml" />
<xi:include href="chapters/access/Attribute_Access.xml" />
<xi:include href="chapters/overrides/Mapping_Overrides.xml" /> AttributeOverrides/AssociationOverrides
<xi:include href="chapters/generation/Generated_attributes.xml" />
columns, formulas, read/write-fragments
<xi:include href="chapters/naming/Naming_Strategies.xml" />
<xi:include href="chapters/quoting/SQL_Identifier_Quoting.xml" />
-->
<!-- appendices? -->

View File

@ -381,32 +381,43 @@
</tgroup>
</table>
<note>
<para>
To use these hibernate-java8 types just add the hibernate-java8 jar to your classpath; Hibernate
will take care of the rest. See <xref linkend="basic-datetime"/>
</para>
</note>
<!-- todo : document added hibernate-spatial types -->
<para>
These mappings are managed by a service inside Hibernate called the
<classname>org.hibernate.type.BasicTypeRegistry</classname>, which essentially maintains a map of
<interface>org.hibernate.type.BasicType</interface> (a <interface>org.hibernate.type.Type</interface>
<interfacename>org.hibernate.type.BasicType</interfacename> (a <interfacename>org.hibernate.type.Type</interfacename>
specialization) instances keyed by a name. That is the purpose of the "BasicTypeRegistry key(s)" column
in the previous tables. We will revisit this detail later.
</para>
</section>
<section xml:id="basic-annotation">
<title>The <literal>@Basic</literal> annotation</title>
<para>
Strictly speaking, a basic type is denoted with the <interfacename>javax.persistence.Basic</interfacename>
annotation. Generally speaking the <literal>@Basic</literal> annotation can be ignored.
annotation. Generally speaking the <literal>@Basic</literal> annotation can be ignored. Both of the
following examples are ultimately the same.
</para>
<example>
<title>With <literal>@Basic</literal></title>
<programlisting role="JAVA"><xi:include href="extras/ex1.java" parse="text"/></programlisting>
</example>
<example>
<title>Without <literal>@Basic</literal></title>
<programlisting role="JAVA"><xi:include href="extras/ex2.java" parse="text"/></programlisting>
</example>
<para>
Both of the above examples are ultimately the same.
</para>
<tip>
<para>
The JPA specification strictly limits the Java types that can be marked as
@ -434,17 +445,71 @@
<para>
If provider portability is a concern, you should stick to just these basic types. Note that JPA
2.1 did add the notion of an <interfacename>javax.persistence.AttributeConverter</interfacename>
to help alleviate some of these concerns; see <xref linked="basic-jpaconvert"/>
to help alleviate some of these concerns; see <xref linkend="basic-jpaconvert"/>
</para>
</tip>
<para>
The <literal>@Basic</literal> annotation defines 2 attributes.
<itemizedlist>
<listitem>
<para>
<literal>optional</literal> - boolean (defaults to true) - Defines whether this attribute
allows nulls. JPA defines this as "a hint", which essentially means that it affect is
specifically required. As long as the type is not primitive, Hibernate takes this to mean
that the underlying column should be <literal>NULLABLE</literal>.
</para>
</listitem>
<listitem>
<para>
<literal>fetch</literal> - FetchType (defaults to EAGER) - Defines whether this attribute
should be fetched eagerly or lazily. JPA says that EAGER is a requirement to the provider
(Hibernate) that the value should be fetched when the owner is fetched but that
LAZY is merely a hint that the value be fetched when the attribute is accessed. Hibernate
ignores this setting for basic types unless you are using bytecode enhancement. See
the <citetitle>Hibernate User Guide</citetitle> for additional information on
fetching and on bytecode enhancement.
</para>
</listitem>
</itemizedlist>
</para>
</section>
<section>
<title>The <literal>@Column</literal> annotation</title>
<para>
JPA defines rules for implicitly determining the name of tables and columns. For a detailed discussion
of implicit naming see <xref linkend="naming"/>.
</para>
<para>
For basic type attributes, the implicit naming rule is that the column name is the same as the attribute
name. If that implicit naming rule does not meet your requirements, you can explicitly tell Hibernate
(and other providers) the column name to use.
</para>
<example>
<title>Explicit column naming</title>
<programlisting role="JAVA"><xi:include href="extras/ExplicitColumnNaming.java" parse="text" /></programlisting>
</example>
<para>
Here we use <literal>@Column</literal> to explicitly map the <literal>description</literal> attribute to the
<literal>NOTES</literal> column, as opposed to the implicit column name <literal>description</literal>.
</para>
<para>
The <literal>@Column</literal> annotation defines other mapping information as well. See its javadocs
for details.
</para>
</section>
<section xml:id="basic-registry">
<title>BasicTypeRegistry</title>
<para>
We said before that a Hibernate type is not a Java type, nor a SQL type, but that it
understands both and performs the marshalling between them. But looking at the
basic type mappings in the previous examples, how did Hibernate know to use
basic type mappings from the previous examples, how did Hibernate know to use
its <classname>org.hibernate.type.StringType</classname> for mapping for
<classname>java.lang.String</classname> attributes or its
<classname>org.hibernate.type.IntegerType</classname> for mapping
@ -454,12 +519,12 @@
<para>
The answer lies in a service inside Hibernate called the
<classname>org.hibernate.type.BasicTypeRegistry</classname>, which essentially maintains a map of
<interface>org.hibernate.type.BasicType</interface> (a <interface>org.hibernate.type.Type</interface>
<interfacename>org.hibernate.type.BasicType</interfacename> (a <interfacename>org.hibernate.type.Type</interfacename>
specialization) instances keyed by a name.
</para>
<para>
We will see later (<xref linked="basic-explicit"/>) that we can explicitly tell Hibernate which
We will see later (<xref linkend="basic-explicit"/>) that we can explicitly tell Hibernate which
BasicType to use for a particular attribute. But first let's explore how implicit resolution works
and how applications can adjust implicit resolution.
</para>
@ -489,7 +554,7 @@
Applications can also extend (add new BasicType registrations) or override (replace an exiting BasicType
registration) using one of the <methodname>MetadataBuilder#applyBasicType</methodname> methods
or the <methodname>MetadataBuilder#applyTypes</methodname> method during bootstrap. For more details, see
<xref linked="basic-custom"/>
<xref linkend="basic-custom"/>
</para>
</section>
@ -514,20 +579,20 @@
<para>
This tells Hibernate to store the Strings as nationalized data. This is just for illustration purposes;
for better ways to indicate nationalized character data see <xref linked="basic-nationalized"/>
for better ways to indicate nationalized character data see <xref linkend="basic-nationalized"/>
</para>
<para>
Additionally the description is to be handled as a LOB. Again, for better ways to indicate
LOBs see <xref linked="basic-lob"/>.
LOBs see <xref linkend="basic-lob"/>.
</para>
<para>
The <methodname>org.hibernate.annotations.Type#type</methodname> attribute can name any of the following:
<itemizedlist>
<listitem>FQN of any <interface>org.hibernate.type.Type</interface> implementation</listitem>
<listitem>Any key registered with BasicTypeRegistry</listitem>
<listitem>The name of any known "type definitions"</listitem>
<listitem><para>FQN of any <interfacename>org.hibernate.type.Type</interfacename> implementation</para></listitem>
<listitem><para>Any key registered with BasicTypeRegistry</para></listitem>
<listitem><para>The name of any known "type definitions"</para></listitem>
</itemizedlist>
</para>
</section>
@ -567,44 +632,386 @@
<programlisting role="JAVA"><xi:include href="extras/FizzywigType2_reg.java" parse="text" /></programlisting>
</example>
<para>
For additional information on developing and registering custom types, see the
<citetitle>Hibernate Integration Guide</citetitle>.
</para>
</section>
<section xml:id="basic-enums">
<title>Mapping enums</title>
<para>
<!-- todo : write -->
blah blah blah
Hibernate supports the mapping of Java enums as basic value types in a number of different ways.
</para>
<section>
<title>@Enumerated</title>
<para>
The original JPA-compliant way to map enums was via the <literal>@Enumerated</literal>
and <literal>@MapKeyEnumerated</literal> for map keys annotations which works on the principle that
the enum values are stored according to one of 2 strategies indicated by
<interfacename>javax.persistence.EnumType</interfacename>:
<itemizedlist>
<listitem>
<para>
<literal>ORDINAL</literal> - stored according to the enum value's ordinal position within
the enum class, as indicated by java.lang.Enum#ordinal
</para>
</listitem>
<listitem>
<para>
<literal>STRING</literal> - stored according to the enum value's name, as indicated by
java.lang.Enum#name
</para>
</listitem>
</itemizedlist>
</para>
<example>
<title>@Enumerated(ORDINAL) example</title>
<programlisting role="JAVA"><xi:include href="extras/EnumeratedOrdinal.java" parse="text" /></programlisting>
</example>
<para>
In the ORDINAL example, the gender column is defined as an (nullable) INTEGER type and would hold:
<itemizedlist>
<listitem>
<para><literal>NULL</literal> - null</para>
</listitem>
<listitem>
<para><literal>0</literal> - MALE</para>
</listitem>
<listitem>
<para><literal>1</literal> - FEMALE</para>
</listitem>
</itemizedlist>
</para>
<example>
<title>@Enumerated(STRING) example</title>
<programlisting role="JAVA"><xi:include href="extras/EnumeratedString.java" parse="text" /></programlisting>
</example>
<para>
In the STRING example, the gender column is defined as an (nullable) VARCHAR type and would hold:
<itemizedlist>
<listitem>
<para><literal>NULL</literal> - null</para>
</listitem>
<listitem>
<para><literal>MALE</literal> - MALE</para>
</listitem>
<listitem>
<para><literal>FEMALE</literal> - FEMALE</para>
</listitem>
</itemizedlist>
</para>
</section>
<section>
<title>AttributeConverter</title>
<para>
You can also map enums in a JPA compliant way using a JPA 2.1 AttributeConverter. Let's revisit the
Gender enum example, but instead we want to store the more standardized <literal>'M'</literal>
and <literal>'F'</literal> codes.
</para>
<example>
<title>Enum mapping with AttributeConverter example</title>
<programlisting role="JAVA"><xi:include href="extras/EnumAttributeConverter.java" parse="text" /></programlisting>
</example>
<para>
Here, the gender column is defined as a CHAR type and would hold:
<itemizedlist>
<listitem>
<para><literal>NULL</literal> - null</para>
</listitem>
<listitem>
<para><literal>'M'</literal> - MALE</para>
</listitem>
<listitem>
<para><literal>'F'</literal> - FEMALE</para>
</listitem>
</itemizedlist>
</para>
<para>
For additional details on using AttributeConverters, see <xref linkend="basic-jpaconvert"/>.
</para>
<para>
Note that JPA explicitly disallows the use of an AttributeConverter with an attribute marked
as <literal>@Enumerated</literal>. So if using the AttributeConverter approach, be sure to not mark the
attribute as <literal>@Enumerated</literal>.
</para>
</section>
<section>
<title>Custom type</title>
<para>
You can also map enums using a Hibernate custom type mapping. Let's again revisit the Gender enum
example, this time using a custom Type to store the more standardized <literal>'M'</literal>
and <literal>'F'</literal> codes.
</para>
<example>
<title>Enum mapping with custom Type example</title>
<programlisting role="JAVA"><xi:include href="extras/EnumCustomType.java" parse="text" /></programlisting>
</example>
<para>
Again, the gender column is defined as a CHAR type and would hold:
<itemizedlist>
<listitem>
<para><literal>NULL</literal> - null</para>
</listitem>
<listitem>
<para><literal>'M'</literal> - MALE</para>
</listitem>
<listitem>
<para><literal>'F'</literal> - FEMALE</para>
</listitem>
</itemizedlist>
</para>
<para>
For additional details on using custom types, see <xref linkend="basic-custom"/>.
</para>
</section>
</section>
<section xml:id="basic-lobs">
<section xml:id="basic-lob">
<title>Mapping LOBs</title>
<para>
<!-- todo : write -->
blah blah blah
Mapping LOBs (database Large OBjects) come in 2 forms, those using the JDBC locator types and those
<firstterm>materializing</firstterm> the LOB data.
</para>
<sidebar>
<title>Locator versus materialized</title>
<para>
JDBC LOB locators exist to allow efficient access to the LOB data. They allow the JDBC driver to
stream parts of the LOB data as needed, potentially freeing up memory space. However they can be
unnatural to deal with and have certain limitations. For example, a LOB locator is only portably
valid during the duration of the transaction in which it was obtained.
</para>
<para>
The idea of materialized LOBs is to trade-off the potential efficiency (not all drivers handle LOB
data efficiently) for a more natural programming paradigm using familiar Java types such as
String or byte[], etc for these LOBs.
</para>
<para>
Materialized deals with the entire LOB contents in memory, whereas LOB locators (in theory) allow
streaming parts of the LOB contents into memory as needed.
</para>
</sidebar>
<para>
The JDBC LOB locator types include:
<itemizedlist>
<listitem>
<para><interfacename>java.sql.Blob</interfacename></para>
<para><interfacename>java.sql.Clob</interfacename></para>
<para><interfacename>java.sql.NClob</interfacename></para>
</listitem>
</itemizedlist>
</para>
<para>
Mapping materialized forms of these LOB values would use more familiar Java types
such as String, char[], byte[], etc. The trade off for "more familiar" is usually
performance.
</para>
<para>
For a first look lets assume we have a CLOB column that we would like to map (NCLOB character LOB data
will be covered in <xref linkend="basic-nationalized"/>).
</para>
<example>
<title>CLOB - SQL</title>
<programlisting role="SQL"><xi:include href="extras/Clob.sql" parse="text" /></programlisting>
</example>
<para>
Let's first map this using the JDBC locator.
</para>
<example>
<title>CLOB - locator mapping</title>
<programlisting role="SQL"><xi:include href="extras/ClobLocator.java" parse="text" /></programlisting>
</example>
<para>
We could also map a materialized form.
</para>
<example>
<title>CLOB - materialized mapping</title>
<programlisting role="SQL"><xi:include href="extras/ClobMaterialized.java" parse="text" /></programlisting>
</example>
<note>
<para>
How JDBC deals with LOB data varies from driver to driver. Hibernate tries to handle all these variances
for you. However some drivers do not allow Hibernate to always do that in an automatic fashion
(looking directly at you PostgreSQL JDBC drivers). In such cases you may have to do some extra
to get LOBs working. Such discussions are beyond the scope of this guide however.
<!-- todo : document known deviations? -->
</para>
</note>
<para>
We might even want the materialized data as a char array (for some crazy reason).
</para>
<example>
<title>CLOB - materialized char[] mapping</title>
<programlisting role="SQL"><xi:include href="extras/ClobMaterializedCharArray.java" parse="text" /></programlisting>
</example>
<para>
We'd map BLOB data in a similar fashion.
</para>
<example>
<title>BLOB - SQL</title>
<programlisting role="SQL"><xi:include href="extras/Blob.sql" parse="text" /></programlisting>
</example>
<para>
Let's first map this using the JDBC locator.
</para>
<example>
<title>BLOB - locator mapping</title>
<programlisting role="SQL"><xi:include href="extras/BlobLocator.java" parse="text" /></programlisting>
</example>
<para>
We could also map a materialized BLOB form.
</para>
<example>
<title>BLOB - materialized mapping</title>
<programlisting role="SQL"><xi:include href="extras/BlobMaterialized.java" parse="text" /></programlisting>
</example>
<!-- todo : alternatives : text, image -->
</section>
<section xml:id="basic-nationalized">
<title>Mapping Nationalized Character Data</title>
<para>
<!-- todo : write -->
blah blah blah
JDBC 4 added the ability to explicitly handle nationalized character data. To this end
it added specific nationalized character data types.
<!-- todo : note that we saw these types above -->
<itemizedlist>
<listitem>
<para><literal>NCHAR</literal></para>
<para><literal>NVARCHAR</literal></para>
<para><literal>LONGNVARCHAR</literal></para>
<para><literal>NCLOB</literal></para>
</listitem>
</itemizedlist>
</para>
<para>
To map a specific attribute to a nationalized variant datatype, Hibernate defines the
<literal>@Nationalized</literal> annotation.
</para>
<example>
<title>NVARCHAR mapping</title>
<programlisting role="SQL"><xi:include href="extras/NVARCHAR.java" parse="text" /></programlisting>
</example>
<example>
<title>NCLOB (locator) mapping</title>
<programlisting role="SQL"><xi:include href="extras/NCLOB_locator.java" parse="text" /></programlisting>
</example>
<example>
<title>NCLOB (materialized) mapping</title>
<programlisting role="SQL"><xi:include href="extras/NCLOB_materialized.java" parse="text" /></programlisting>
</example>
<para>
If you application and database are entirely nationalized you may instead want to enable nationalized
character data as the default. You can do this via the
<literal>hibernate.use_nationalized_character_data</literal> setting or by calling
<methodname>MetadataBuilder#enableGlobalNationalizedCharacterDataSupport</methodname> during bootstrap.
</para>
</section>
<section xml:id="basic-uuid">
<title>Mapping UUID Values</title>
<para>
<!-- todo : write -->
blah blah blah
Hibernate also allows you to map UUID values, again in a number of ways.
</para>
<note>
<para>
The default UUID mapping is as binary because it represents more efficient storage. However
many applications prefer the readability of character storage. To switch the default mapping,
simply call <literal>MetadataBuilder.applyBasicType( UUIDCharType.INSTANCE, UUID.class.getName() )</literal>
</para>
</note>
<section>
<title>UUID as binary</title>
<para>
As mentioned, the default mapping for UUID attributes. Maps the UUID to a byte[]
using java.util.UUID#getMostSignificantBits and java.util.UUID#getLeastSignificantBits
and stores that as BINARY data.
</para>
<para>
Chosen as the default simply because it is generally more efficient from storage perspective.
</para>
</section>
<section>
<title>UUID as (var)char</title>
<para>
Maps the UUID to a String using java.util.UUID#toString and java.util.UUID#fromString
and stores that as CHAR or VARCHAR data.
</para>
</section>
<section>
<title>PostgeSQL-specific UUID</title>
<important>
<para>When using one of the PostgreSQL Dialects, this becomes the default UUID mapping</para>
</important>
<para>
Maps the UUID using PostgreSQL's specific UUID data type. The PostgreSQL JDBC driver choses to
map its UUID type to the <literal>OTHER</literal> code. Note that this can cause difficulty as the
driver chooses to map many different data types to OTHER.
</para>
</section>
<section>
<title>UUID as identifier</title>
<para>
Hibernate supports using UUID values as identifiers. They can even be generated! For
details see the discussion of generators in <xref linkend="identifiers"/>
</para>
</section>
</section>
<section xml:id="basic-datetime">
<title>Mapping Date/Time Values</title>
<para>
<!-- todo : write -->
<!-- todo : highly recommend java8 types (or joda time) -->
blah blah blah
</para>
</section>

View File

@ -0,0 +1,5 @@
create table step(
...
instruction BLOB not null,
...
)

View File

@ -0,0 +1,8 @@
@Entity
public class Step {
...
@Lob
@Basic
public Blob instructions;
...
}

View File

@ -0,0 +1,8 @@
@Entity
public class Step {
...
@Lob
@Basic
public byte[] instructions;
...
}

View File

@ -0,0 +1,5 @@
create table product(
...
description CLOB not null,
...
)

View File

@ -0,0 +1,8 @@
@Entity
public class Product {
...
@Lob
@Basic
public Clob description;
...
}

View File

@ -0,0 +1,8 @@
@Entity
public class Product {
...
@Lob
@Basic
public String description;
...
}

View File

@ -0,0 +1,8 @@
@Entity
public class Product {
...
@Lob
@Basic
public char[] description;
...
}

View File

@ -0,0 +1,53 @@
@Entity
public class Person {
...
@Basic
@Convert( converter=GenderConverter.class )
public Gender gender;
}
public enum Gender {
MALE( 'M' ),
FEMALE( 'F' );
private final char code;
private Gender(char code) {
this.code = code;
}
public char getCode() {
return code;
}
public static Gender fromCode(char code) {
if ( code == 'M' || code == 'm' ) {
return MALE;
}
if ( code == 'F' || code == 'f' ) {
return FEMALE;
}
throw ...
}
}
@Converter
public class GenderConverter
implements AttributeConverter<Character,Gender> {
public Character convertToDatabaseColumn(Gender value) {
if ( value == null ) {
return null;
}
return value.getCode();
}
public Gender convertToEntityAttribute(Character value) {
if ( value == null ) {
return null;
}
return Gender.fromCode( value );
}
}

View File

@ -0,0 +1,82 @@
import org.hibernate.type.descriptor.java.CharacterTypeDescriptor;
@Entity
public class Person {
...
@Basic
@Type( type = GenderType.class )
public Gender gender;
}
public enum Gender {
MALE( 'M' ),
FEMALE( 'F' );
private final char code;
private Gender(char code) {
this.code = code;
}
public char getCode() {
return code;
}
public static Gender fromCode(char code) {
if ( code == 'M' || code == 'm' ) {
return MALE;
}
if ( code == 'F' || code == 'f' ) {
return FEMALE;
}
throw ...
}
}
@Converter
public class GenderType
extends AbstractSingleColumnStandardBasicType<Gender> {
public static final GenderType INSTANCE = new GenderType();
private GenderType() {
super(
CharTypeDescriptor.INSTANCE,
GenderJavaTypeDescriptor.INSTANCE
);
}
public String getName() {
return "gender";
}
@Override
protected boolean registerUnderJavaType() {
return true;
}
}
public static class GenderJavaTypeDescriptor
extends AbstractTypeDescriptor<Gender> {
public static final GenderJavaTypeDescriptor INSTANCE = new GenderJavaTypeDescriptor();
public String toString(Gender value) {
return value == null ? null : value.name();
}
public Gender fromString(String string) {
return string == null ? null : Gender.valueOf( string );
}
public <X> X unwrap(Gender value, Class<X> type, WrapperOptions options) {
return CharacterTypeDescriptor.INSTANCE.unwrap(
value == null ? null : value.getCode(),
type,
options
);
}
public <X> Gender wrap(X value, WrapperOptions options) {
return CharacterTypeDescriptor.INSTANCE.wrap( value, options );
}
}

View File

@ -0,0 +1,11 @@
@Entity
public class Person {
...
@Enumerated
public Gender gender;
public static enum Gender {
MALE,
FEMALE
}
}

View File

@ -0,0 +1,11 @@
@Entity
public class Person {
...
@Enumerated(STRING)
public Gender gender;
public static enum Gender {
MALE,
FEMALE
}
}

View File

@ -0,0 +1,13 @@
@Entity
public class Product {
@Id
@Basic
private Integer id;
@Basic
private String sku;
@Basic
private String name;
@Basic
@Column( name = "NOTES" )
private String description;
}

View File

@ -0,0 +1,12 @@
@Entity
public class Product {
...
@Lob
@Basic
@Nationalized
public NClob description;
// Clob also works, because NClob
// extends Clob. The db type is
// still NCLOB either way and
// handled as such
}

View File

@ -0,0 +1,8 @@
@Entity
public class Product {
...
@Lob
@Basic
@Nationalized
public String description;
}

View File

@ -0,0 +1,8 @@
@Entity
public class Product {
...
@Basic
@Nationalized
public String description;
...
}

View File

@ -73,7 +73,7 @@
<title>Bags</title>
<para>
<!-- todo : discuss mapping bags -->
todo : discuss mapping bags
todo : discuss mapping bags and idbags
</para>
</section>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<chapter xml:id="entity"
version="5.0"
xml:lang="en"
xmlns="http://docbook.org/ns/docbook"
>
<title>Entity</title>
<para>
* POJO, etc discussion from manual/en-US/chapters/domain/DomainModel.xml
* dynamic models (hbm.xml)
* Map mode
* proxy solutions (hibernate-core/src/test/java/org/hibernate/test/dynamicentity/tuplizer2)
* inheritance
* optimistic locking
</para>
</chapter>

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<chapter xml:id="identifiers"
version="5.0"
xml:lang="en"
xmlns="http://docbook.org/ns/docbook"
>
<title>Identifiers</title>
<para>
Identifiers model the primary key of an entity. They are used to uniquely identify each
specific entity. Every entity must define an identifier.
</para>
<note>
<para>
Technically the identifier does not have to map to the column(s) physically defined as the entity
table's primary key. They just need to map to column(s) that uniquely identify each row. However
this documentation will continue to use the terms identifier and primary key interchangeably.
</para>
</note>
<para>
An identifier might be simple (single value) or composite (multiple values).
</para>
<!-- todo : be sure to discuss generators in simple, then reference from composite -->
<section>
<title>Simple identifiers</title>
<para></para>
</section>
<section>
<title>Composite identifiers</title>
<para></para>
<section>
<title>Composite identifiers - aggregated</title>
<para></para>
</section>
<section>
<title>Composite identifiers - non-aggregated</title>
<para></para>
</section>
</section>
</chapter>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<chapter xml:id="naturalid"
version="5.0"
xml:lang="en"
xmlns="http://docbook.org/ns/docbook"
>
<title>Natural Ids</title>
<para>
* simple
* composite
* caching
* apis
</para>
</chapter>

View File

@ -308,6 +308,17 @@ public interface MetadataBuilder {
*/
MetadataBuilder applyBasicType(BasicType type);
/**
* Specify an additional or overridden basic type mapping supplying specific
* registration keys.
*
* @param type The type addition or override.
* @param keys The keys under which to register the basic type.
*
* @return {@code this}, for method chaining
*/
MetadataBuilder applyBasicType(BasicType type, String... keys);
/**
* Register an additional or overridden custom type mapping.
*
@ -316,7 +327,7 @@ public interface MetadataBuilder {
*
* @return {@code this}, for method chaining
*/
MetadataBuilder applyBasicType(UserType type, String[] keys);
MetadataBuilder applyBasicType(UserType type, String... keys);
/**
* Register an additional or overridden composite custom type mapping.
@ -326,7 +337,7 @@ public interface MetadataBuilder {
*
* @return {@code this}, for method chaining
*/
MetadataBuilder applyBasicType(CompositeUserType type, String[] keys);
MetadataBuilder applyBasicType(CompositeUserType type, String... keys);
/**
* Apply an explicit TypeContributor (implicit application via ServiceLoader will still happen too)

View File

@ -12,7 +12,6 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.AttributeConverter;
import javax.persistence.SharedCacheMode;
@ -50,6 +49,7 @@ import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.selector.spi.StrategySelector;
import org.hibernate.boot.spi.BasicTypeRegistration;
import org.hibernate.boot.spi.JpaOrmXmlPersistenceUnitDefaultAware;
import org.hibernate.boot.spi.MappingDefaults;
import org.hibernate.boot.spi.MetadataBuilderImplementor;
@ -72,10 +72,9 @@ import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.BasicType;
import org.hibernate.type.CompositeCustomType;
import org.hibernate.type.CustomType;
import org.hibernate.usertype.CompositeUserType;
import org.hibernate.usertype.UserType;
import org.jboss.jandex.IndexView;
import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER;
@ -252,19 +251,25 @@ public class MetadataBuilderImpl implements MetadataBuilderImplementor, TypeCont
@Override
public MetadataBuilder applyBasicType(BasicType type) {
options.basicTypeRegistrations.add( type );
options.basicTypeRegistrations.add( new BasicTypeRegistration( type ) );
return this;
}
@Override
public MetadataBuilder applyBasicType(UserType type, String[] keys) {
options.basicTypeRegistrations.add( new CustomType( type, keys ) );
public MetadataBuilder applyBasicType(BasicType type, String... keys) {
options.basicTypeRegistrations.add( new BasicTypeRegistration( type, keys ) );
return this;
}
@Override
public MetadataBuilder applyBasicType(CompositeUserType type, String[] keys) {
options.basicTypeRegistrations.add( new CompositeCustomType( type, keys ) );
public MetadataBuilder applyBasicType(UserType type, String... keys) {
options.basicTypeRegistrations.add( new BasicTypeRegistration( type, keys ) );
return this;
}
@Override
public MetadataBuilder applyBasicType(CompositeUserType type, String... keys) {
options.basicTypeRegistrations.add( new BasicTypeRegistration( type, keys ) );
return this;
}
@ -276,17 +281,22 @@ public class MetadataBuilderImpl implements MetadataBuilderImplementor, TypeCont
@Override
public void contributeType(BasicType type) {
options.basicTypeRegistrations.add( type );
options.basicTypeRegistrations.add( new BasicTypeRegistration( type ) );
}
@Override
public void contributeType(BasicType type, String... keys) {
options.basicTypeRegistrations.add( new BasicTypeRegistration( type, keys ) );
}
@Override
public void contributeType(UserType type, String[] keys) {
options.basicTypeRegistrations.add( new CustomType( type, keys ) );
options.basicTypeRegistrations.add( new BasicTypeRegistration( type, keys ) );
}
@Override
public void contributeType(CompositeUserType type, String[] keys) {
options.basicTypeRegistrations.add( new CompositeCustomType( type, keys ) );
options.basicTypeRegistrations.add( new BasicTypeRegistration( type, keys ) );
}
@Override
@ -523,7 +533,7 @@ public class MetadataBuilderImpl implements MetadataBuilderImplementor, TypeCont
private final StandardServiceRegistry serviceRegistry;
private final MappingDefaultsImpl mappingDefaults;
private ArrayList<BasicType> basicTypeRegistrations = new ArrayList<BasicType>();
private ArrayList<BasicTypeRegistration> basicTypeRegistrations = new ArrayList<BasicTypeRegistration>();
private IndexView jandexView;
private ClassLoader tempClassLoader;
@ -747,7 +757,7 @@ public class MetadataBuilderImpl implements MetadataBuilderImplementor, TypeCont
}
@Override
public List<BasicType> getBasicTypeRegistrations() {
public List<BasicTypeRegistration> getBasicTypeRegistrations() {
return basicTypeRegistrations;
}

View File

@ -16,9 +16,11 @@ import org.hibernate.usertype.UserType;
* @author Steve Ebersole
*/
public interface TypeContributions {
public void contributeType(BasicType type);
void contributeType(BasicType type);
public void contributeType(UserType type, String... keys);
void contributeType(BasicType type, String... keys);
public void contributeType(CompositeUserType type, String... keys);
void contributeType(UserType type, String... keys);
void contributeType(CompositeUserType type, String... keys);
}

View File

@ -28,6 +28,7 @@ import org.hibernate.boot.model.source.internal.hbm.ModelBinder;
import org.hibernate.boot.model.source.spi.MetadataSourceProcessor;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.spi.AdditionalJaxbMappingProducer;
import org.hibernate.boot.spi.BasicTypeRegistration;
import org.hibernate.boot.spi.ClassLoaderAccess;
import org.hibernate.boot.spi.MetadataBuildingOptions;
import org.hibernate.boot.spi.MetadataContributor;
@ -36,6 +37,7 @@ import org.hibernate.cfg.AttributeConverterDefinition;
import org.hibernate.cfg.MetadataSourceType;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.type.BasicType;
import org.hibernate.type.BasicTypeRegistry;
import org.hibernate.type.TypeFactory;
import org.hibernate.type.TypeResolver;
@ -330,6 +332,11 @@ public class MetadataBuildingProcess {
basicTypeRegistry.register( type );
}
@Override
public void contributeType(BasicType type, String... keys) {
basicTypeRegistry.register( type, keys );
}
@Override
public void contributeType(UserType type, String[] keys) {
basicTypeRegistry.register( type, keys );
@ -351,8 +358,11 @@ public class MetadataBuildingProcess {
}
// add explicit application registered types
for ( org.hibernate.type.BasicType basicType : options.getBasicTypeRegistrations() ) {
basicTypeRegistry.register( basicType );
for ( BasicTypeRegistration basicTypeRegistration : options.getBasicTypeRegistrations() ) {
basicTypeRegistry.register(
basicTypeRegistration.getBasicType(),
basicTypeRegistration.getRegistrationKeys()
);
}
return basicTypeRegistry;

View File

@ -28,6 +28,7 @@ import org.hibernate.dialect.function.SQLFunction;
import org.hibernate.type.BasicType;
import org.hibernate.usertype.CompositeUserType;
import org.hibernate.usertype.UserType;
import org.jboss.jandex.IndexView;
/**
@ -38,6 +39,7 @@ import org.jboss.jandex.IndexView;
* @param <T> The type of a specific sub-class; Allows sub-classes to narrow down the return-type of the contract methods
* to a specialization of {@link MetadataBuilderImplementor}
*/
@SuppressWarnings("unused")
public abstract class AbstractDelegatingMetadataBuilderImplementor<T extends AbstractDelegatingMetadataBuilderImplementor<T>> implements MetadataBuilderImplementor {
private final MetadataBuilderImplementor delegate;
@ -166,13 +168,19 @@ public abstract class AbstractDelegatingMetadataBuilderImplementor<T extends Abs
}
@Override
public MetadataBuilder applyBasicType(UserType type, String[] keys) {
public MetadataBuilder applyBasicType(BasicType type, String... keys) {
delegate.applyBasicType( type, keys );
return getThis();
}
@Override
public MetadataBuilder applyBasicType(CompositeUserType type, String[] keys) {
public MetadataBuilder applyBasicType(UserType type, String... keys) {
delegate.applyBasicType( type, keys );
return getThis();
}
@Override
public MetadataBuilder applyBasicType(CompositeUserType type, String... keys) {
delegate.applyBasicType( type, keys );
return getThis();
}

View File

@ -8,7 +8,6 @@ package org.hibernate.boot.spi;
import java.util.List;
import java.util.Map;
import javax.persistence.SharedCacheMode;
import org.hibernate.HibernateException;
@ -27,7 +26,7 @@ import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cfg.AttributeConverterDefinition;
import org.hibernate.cfg.MetadataSourceType;
import org.hibernate.dialect.function.SQLFunction;
import org.hibernate.type.BasicType;
import org.jboss.jandex.IndexView;
/**
@ -56,7 +55,7 @@ public abstract class AbstractDelegatingMetadataBuildingOptions implements Metad
}
@Override
public List<BasicType> getBasicTypeRegistrations() {
public List<BasicTypeRegistration> getBasicTypeRegistrations() {
return delegate.getBasicTypeRegistrations();
}

View File

@ -0,0 +1,46 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.boot.spi;
import org.hibernate.type.BasicType;
import org.hibernate.type.CompositeCustomType;
import org.hibernate.type.CustomType;
import org.hibernate.usertype.CompositeUserType;
import org.hibernate.usertype.UserType;
/**
* @author Steve Ebersole
*/
public class BasicTypeRegistration {
private final BasicType basicType;
private final String[] registrationKeys;
public BasicTypeRegistration(BasicType basicType) {
this( basicType, basicType.getRegistrationKeys() );
}
public BasicTypeRegistration(BasicType basicType, String[] registrationKeys) {
this.basicType = basicType;
this.registrationKeys = registrationKeys;
}
public BasicTypeRegistration(UserType type, String[] keys) {
this( new CustomType( type, keys ), keys );
}
public BasicTypeRegistration(CompositeUserType type, String[] keys) {
this( new CompositeCustomType( type, keys ), keys );
}
public BasicType getBasicType() {
return basicType;
}
public String[] getRegistrationKeys() {
return registrationKeys;
}
}

View File

@ -25,7 +25,6 @@ import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cfg.AttributeConverterDefinition;
import org.hibernate.cfg.MetadataSourceType;
import org.hibernate.dialect.function.SQLFunction;
import org.hibernate.type.BasicType;
import org.jboss.jandex.IndexView;
@ -56,13 +55,14 @@ public interface MetadataBuildingOptions {
* Access the list of BasicType registrations. These are the BasicTypes explicitly
* registered via calls to:<ul>
* <li>{@link org.hibernate.boot.MetadataBuilder#applyBasicType(org.hibernate.type.BasicType)}</li>
* <li>{@link org.hibernate.boot.MetadataBuilder#applyBasicType(org.hibernate.type.BasicType, String[])}</li>
* <li>{@link org.hibernate.boot.MetadataBuilder#applyBasicType(org.hibernate.usertype.UserType, java.lang.String[])}</li>
* <li>{@link org.hibernate.boot.MetadataBuilder#applyBasicType(org.hibernate.usertype.CompositeUserType, java.lang.String[])}</li>
* </ul>
*
* @return The BasicType registrations
*/
List<BasicType> getBasicTypeRegistrations();
List<BasicTypeRegistration> getBasicTypeRegistrations();
/**
* Access to the Jandex index passed by call to

View File

@ -110,6 +110,10 @@ public class BasicTypeRegistry implements Serializable {
}
public void register(BasicType type) {
register( type, type.getRegistrationKeys() );
}
public void register(BasicType type, String[] keys) {
if ( locked ) {
throw new HibernateException( "Can not alter TypeRegistry at this time" );
}
@ -118,11 +122,12 @@ public class BasicTypeRegistry implements Serializable {
throw new HibernateException( "Type to register cannot be null" );
}
if ( type.getRegistrationKeys() == null || type.getRegistrationKeys().length == 0 ) {
if ( keys == null || keys.length == 0 ) {
LOG.typeDefinedNoRegistrationKeys( type );
return;
}
for ( String key : type.getRegistrationKeys() ) {
for ( String key : keys ) {
// be safe...
if ( key == null ) {
continue;