Migrate BasicType and UserType User Guide examples to unit tests
This commit is contained in:
parent
58c6c7a98a
commit
2abcab0501
|
@ -16,7 +16,7 @@ With the coming of JPA, most of this information is now defined in a way that is
|
||||||
This chapter will focus on JPA mapping where possible.
|
This chapter will focus on JPA mapping where possible.
|
||||||
For Hibernate mapping features not supported by JPA we will prefer Hibernate extension annotations.
|
For Hibernate mapping features not supported by JPA we will prefer Hibernate extension annotations.
|
||||||
|
|
||||||
include::mapping_types.adoc[]
|
include::types.adoc[]
|
||||||
include::naming.adoc[]
|
include::naming.adoc[]
|
||||||
include::basic_types.adoc[]
|
include::basic_types.adoc[]
|
||||||
include::embeddables.adoc[]
|
include::embeddables.adoc[]
|
||||||
|
|
|
@ -93,19 +93,21 @@ Strictly speaking, a basic type is denoted with with the `javax.persistence.Basi
|
||||||
Generally speaking the `@Basic` annotation can be ignored, as it is assumed by default.
|
Generally speaking the `@Basic` annotation can be ignored, as it is assumed by default.
|
||||||
Both of the following examples are ultimately the same.
|
Both of the following examples are ultimately the same.
|
||||||
|
|
||||||
.With `@Basic`
|
[[basic-annotation-explicit-example]]
|
||||||
|
.`@Basic` declared explicitly
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
include::{extrasdir}/basic/ex1.java[]
|
include::{sourcedir}/basic/ExplicitBasicTypeTest.java[tags=basic-annotation-explicit-example]
|
||||||
----
|
----
|
||||||
====
|
====
|
||||||
|
|
||||||
.Without `@Basic`
|
[[basic-annotation-implicit-example]]
|
||||||
|
.`@Basic` being implicitly implied
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
include::{extrasdir}/basic/ex2.java[]
|
include::{sourcedir}/basic/ImplicitBasicTypeTest.java[tags=basic-annotation-implicit-example]
|
||||||
----
|
----
|
||||||
====
|
====
|
||||||
|
|
||||||
|
@ -142,6 +144,7 @@ JPA says that EAGER is a requirement to the provider (Hibernate) that the value
|
||||||
Hibernate ignores this setting for basic types unless you are using bytecode enhancement.
|
Hibernate ignores this setting for basic types unless you are using bytecode enhancement.
|
||||||
See the <chapters/pc/BytecodeEnhancement.adoc#BytecodeEnhancement,BytecodeEnhancement>> for additional information on fetching and on bytecode enhancement.
|
See the <chapters/pc/BytecodeEnhancement.adoc#BytecodeEnhancement,BytecodeEnhancement>> for additional information on fetching and on bytecode enhancement.
|
||||||
|
|
||||||
|
[[basic-column-annotation]]
|
||||||
==== The `@Column` annotation
|
==== The `@Column` annotation
|
||||||
|
|
||||||
JPA defines rules for implicitly determining the name of tables and columns.
|
JPA defines rules for implicitly determining the name of tables and columns.
|
||||||
|
@ -150,11 +153,12 @@ For a detailed discussion of implicit naming see <<naming.adoc#naming,Naming>>.
|
||||||
For basic type attributes, the implicit naming rule is that the column name is the same as the attribute name.
|
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.
|
If that implicit naming rule does not meet your requirements, you can explicitly tell Hibernate (and other providers) the column name to use.
|
||||||
|
|
||||||
|
[[basic-annotation-explicit-column-example]]
|
||||||
.Explicit column naming
|
.Explicit column naming
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
include::{extrasdir}/basic/ExplicitColumnNaming.java[]
|
include::{sourcedir}/basic/ExplicitColumnNamingTest.java[tags=basic-annotation-explicit-column-example]
|
||||||
----
|
----
|
||||||
====
|
====
|
||||||
|
|
||||||
|
@ -172,7 +176,7 @@ or its `org.hibernate.type.IntegerType` for mapping `java.lang.Integer` attribut
|
||||||
|
|
||||||
The answer lies in a service inside Hibernate called the `org.hibernate.type.BasicTypeRegistry`, which essentially maintains a map of `org.hibernate.type.BasicType` (a `org.hibernate.type.Type` specialization) instances keyed by a name.
|
The answer lies in a service inside Hibernate called the `org.hibernate.type.BasicTypeRegistry`, which essentially maintains a map of `org.hibernate.type.BasicType` (a `org.hibernate.type.Type` specialization) instances keyed by a name.
|
||||||
|
|
||||||
We will see later, in the <<basic-explicit>> section, that we can explicitly tell Hibernate which BasicType to use for a particular attribute.
|
We will see later, in the <<basic-type-annotation>> section, 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.
|
But first let's explore how implicit resolution works and how applications can adjust implicit resolution.
|
||||||
|
|
||||||
[NOTE]
|
[NOTE]
|
||||||
|
@ -191,9 +195,9 @@ So that is the baseline mapping within `BasicTypeRegistry` for Strings.
|
||||||
|
|
||||||
Applications can also extend (add new `BasicType` registrations) or override (replace an exiting `BasicType` registration) using one of the
|
Applications can also extend (add new `BasicType` registrations) or override (replace an exiting `BasicType` registration) using one of the
|
||||||
`MetadataBuilder#applyBasicType` methods or the `MetadataBuilder#applyTypes` method during bootstrap.
|
`MetadataBuilder#applyBasicType` methods or the `MetadataBuilder#applyTypes` method during bootstrap.
|
||||||
For more details, see <<basic-custom>> section.
|
For more details, see <<basic-custom-type>> section.
|
||||||
|
|
||||||
[[basic-explicit]]
|
[[basic-type-annotation]]
|
||||||
==== Explicit BasicTypes
|
==== Explicit BasicTypes
|
||||||
|
|
||||||
Sometimes you want a particular attribute to be handled differently.
|
Sometimes you want a particular attribute to be handled differently.
|
||||||
|
@ -201,11 +205,12 @@ Occasionally Hibernate will implicitly pick a `BasicType` that you do not want (
|
||||||
|
|
||||||
In these cases you must explicitly tell Hibernate the `BasicType` to use, via the `org.hibernate.annotations.Type` annotation.
|
In these cases you must explicitly tell Hibernate the `BasicType` to use, via the `org.hibernate.annotations.Type` annotation.
|
||||||
|
|
||||||
|
[[basic-type-annotation-example]]
|
||||||
.Using `@org.hibernate.annotations.Type`
|
.Using `@org.hibernate.annotations.Type`
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
include::{extrasdir}/basic/explicitType.java[]
|
include::{sourcedir}/basic/ExplicitTypeTest.java[tags=basic-type-annotation-example]
|
||||||
----
|
----
|
||||||
====
|
====
|
||||||
|
|
||||||
|
@ -218,49 +223,176 @@ The `org.hibernate.annotations.Type#type` attribute can name any of the followin
|
||||||
|
|
||||||
* Fully qualified name of any `org.hibernate.type.Type` implementation
|
* Fully qualified name of any `org.hibernate.type.Type` implementation
|
||||||
* Any key registered with `BasicTypeRegistry`
|
* Any key registered with `BasicTypeRegistry`
|
||||||
* The name of any known "type definitions"
|
* The name of any known _type definitions_
|
||||||
|
|
||||||
[[basic-custom]]
|
[[basic-custom-type]]
|
||||||
==== Custom BasicTypes
|
==== Custom BasicTypes
|
||||||
|
|
||||||
Hibernate makes it relatively easy for developers to create their own basic type mappings type.
|
Hibernate makes it relatively easy for developers to create their own basic type mappings type.
|
||||||
For example, you might want to persist properties of type `java.lang.BigInteger` to `VARCHAR` columns, or support completely new types.
|
For example, you might want to persist properties of type `java.util.BigInteger` to `VARCHAR` columns, or support completely new types.
|
||||||
|
|
||||||
There are two approaches to developing a custom BasicType.
|
There are two approaches to developing a custom type:
|
||||||
As a means of illustrating the different approaches, let's consider a use case where we need to support a class called `Fizzywig` from a third party library.
|
|
||||||
Let's assume that Fizzywig naturally stores as a VARCHAR.
|
|
||||||
|
|
||||||
The first approach is to directly implement the BasicType interface.
|
- implementing a `BasicType` and registering it
|
||||||
|
- implement a `UserType` which doesn't require type registration
|
||||||
|
|
||||||
.Custom BasicType implementation
|
As a means of illustrating the different approaches, let's consider a use case where we need to support a `java.util.BitSet` mapping that's stored as a VARCHAR.
|
||||||
|
|
||||||
|
[[basic-custom-type-BasicType]]
|
||||||
|
===== Implementing a `BasicType`
|
||||||
|
|
||||||
|
The first approach is to directly implement the `BasicType` interface.
|
||||||
|
|
||||||
|
[NOTE]
|
||||||
|
====
|
||||||
|
Because the `BasicType` interface has a lot of methods to implement, it's much more convenient to extend the `AbstractStandardBasicType`,
|
||||||
|
or the `AbstractSingleColumnStandardBasicType` if the value is stored in a single database column.
|
||||||
====
|
====
|
||||||
[source,java]
|
|
||||||
----
|
|
||||||
include::{extrasdir}/basic/FizzywigType1.java[]
|
|
||||||
----
|
|
||||||
|
|
||||||
[source,java]
|
First, we need to extend the `AbstractSingleColumnStandardBasicType` like this:
|
||||||
|
|
||||||
|
[[basic-custom-type-BitSetType-example]]
|
||||||
|
.Custom `BasicType` implementation
|
||||||
|
====
|
||||||
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
include::{extrasdir}/basic/FizzywigType1_reg.java[]
|
include::{sourcedir}/basic/BitSetType.java[tags=basic-custom-type-BitSetType-example]
|
||||||
----
|
----
|
||||||
====
|
====
|
||||||
|
|
||||||
The second approach is to implement the UserType interface.
|
The `AbstractSingleColumnStandardBasicType` requires an `sqlTypeDescriptor` and a `javaTypeDescriptor`.
|
||||||
|
The `sqlTypeDescriptor` is `VarcharTypeDescriptor.INSTANCE` because the database column is a VARCHAR.
|
||||||
|
On the Java side, we need to use a `BitSetTypeDescriptor` instance which can be implemented like this:
|
||||||
|
|
||||||
.Custom UserType implementation
|
[[basic-custom-type-BitSetTypeDescriptor-example]]
|
||||||
|
.Custom `AbstractTypeDescriptor` implementation
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
include::{extrasdir}/basic/FizzywigType2.java[]
|
include::{sourcedir}/basic/BitSetTypeDescriptor.java[tags=basic-custom-type-BitSetTypeDescriptor-example]
|
||||||
----
|
|
||||||
|
|
||||||
[source,java]
|
|
||||||
----
|
|
||||||
include::{extrasdir}/basic/FizzywigType2_reg.java[]
|
|
||||||
----
|
----
|
||||||
====
|
====
|
||||||
|
|
||||||
For additional information on developing and registering custom types, see the Hibernate Integration Guide.
|
The `unwrap` method is used when passing a `BitSet` as a `PreparedStatement` bind parameter, while the `wrap` method is used to transform the JDBC column value object (e.g. `String` in our case) to the actual mapping object type (e.g. `BitSet` in this example).
|
||||||
|
|
||||||
|
The `BasicType` must be registered, and this can be done at bootstrapping time:
|
||||||
|
|
||||||
|
[[basic-custom-type-register-BasicType-example]]
|
||||||
|
.Register a Custom `BasicType` implementation
|
||||||
|
====
|
||||||
|
[source, JAVA, indent=0]
|
||||||
|
----
|
||||||
|
include::{sourcedir}/basic/BitSetTypeTest.java[tags=basic-custom-type-register-BasicType-example]
|
||||||
|
----
|
||||||
|
|
||||||
|
or using the `MetadataBuilder`
|
||||||
|
|
||||||
|
[source, JAVA, indent=0]
|
||||||
|
----
|
||||||
|
include::{sourcedir}/../bootstrap/BootstrapTest.java[tags=basic-custom-type-register-BasicType-example]
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
With the new `BitSetType` being registered as `bitset`, the entity mapping looks like this:
|
||||||
|
|
||||||
|
[[basic-custom-type-BitSetType-mapping-example]]
|
||||||
|
.Custom `BasicType` mapping
|
||||||
|
====
|
||||||
|
[source, JAVA, indent=0]
|
||||||
|
----
|
||||||
|
include::{sourcedir}/basic/BitSetTypeTest.java[tags=basic-custom-type-BitSetType-mapping-example]
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
To validate this new `BasicType` implementation, we can test it as follows:
|
||||||
|
|
||||||
|
[[basic-custom-type-BitSetType-persistence-example]]
|
||||||
|
.Persisting the custom `BasicType`
|
||||||
|
====
|
||||||
|
[source, JAVA, indent=0]
|
||||||
|
----
|
||||||
|
include::{sourcedir}/basic/BitSetTypeTest.java[tags=basic-custom-type-BitSetType-persistence-example]
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
When executing this unit test, Hibernate generates the following SQL statements:
|
||||||
|
|
||||||
|
[[basic-custom-type-BitSetType-persistence-sql-example]]
|
||||||
|
.Persisting the custom `BasicType`
|
||||||
|
====
|
||||||
|
[source, JAVA, indent=0]
|
||||||
|
----
|
||||||
|
include::{extrasdir}/basic/basic-custom-type-BitSetType-persistence-sql-example.sql[]
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
As you can see, the `BitSetType` takes care of the _Java-to-SQL_ and _SQL-to-Java_ type conversion.
|
||||||
|
|
||||||
|
[[basic-custom-type-UserType]]
|
||||||
|
===== Implementing a `UserType`
|
||||||
|
|
||||||
|
The second approach is to implement the `UserType` interface.
|
||||||
|
|
||||||
|
[[basic-custom-type-BitSetUserType-example]]
|
||||||
|
.Custom `UserType` implementation
|
||||||
|
====
|
||||||
|
[source, JAVA, indent=0]
|
||||||
|
----
|
||||||
|
include::{sourcedir}/basic/BitSetUserType.java[tags=basic-custom-type-BitSetUserType-example]
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
The entity mapping looks as follows:
|
||||||
|
|
||||||
|
[[basic-custom-type-BitSetUserType-mapping-example]]
|
||||||
|
.Custom `UserType` mapping
|
||||||
|
====
|
||||||
|
[source, JAVA, indent=0]
|
||||||
|
----
|
||||||
|
include::{sourcedir}/basic/BitSetUserTypeTest.java[tags=basic-custom-type-BitSetUserType-mapping-example]
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
In this example, the `UserType` is registered under the `bitset` name, and this is done like this:
|
||||||
|
|
||||||
|
[[basic-custom-type-register-UserType-example]]
|
||||||
|
.Register a Custom `UserType` implementation
|
||||||
|
====
|
||||||
|
[source, JAVA, indent=0]
|
||||||
|
----
|
||||||
|
include::{sourcedir}/basic/BitSetUserTypeTest.java[tags=basic-custom-type-register-UserType-example]
|
||||||
|
----
|
||||||
|
|
||||||
|
or using the `MetadataBuilder`
|
||||||
|
|
||||||
|
[source, JAVA, indent=0]
|
||||||
|
----
|
||||||
|
include::{sourcedir}/../bootstrap/BootstrapTest.java[tags=basic-custom-type-register-UserType-example]
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
[NOTE]
|
||||||
|
====
|
||||||
|
Like `BasicType`, you can also register the `UserType` using a simple name.
|
||||||
|
|
||||||
|
Without registration, the `UserType` mapping requires the fully-classified name:
|
||||||
|
|
||||||
|
[source, JAVA, indent=0]
|
||||||
|
----
|
||||||
|
@Type( type = "org.hibernate.userguide.mapping.basic.BitSetUserType" )
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
When running the previous test case against the `BitSetUserType` entity mapping, Hibernate executed the following SQL statements:
|
||||||
|
|
||||||
|
[[basic-custom-type-BitSetUserType-persistence-sql-example]]
|
||||||
|
.Persisting the custom `BasicType`
|
||||||
|
====
|
||||||
|
[source, JAVA, indent=0]
|
||||||
|
----
|
||||||
|
include::{extrasdir}/basic/basic-custom-type-BitSetUserType-persistence-sql-example.sql[]
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
[[basic-enums]]
|
[[basic-enums]]
|
||||||
==== Mapping enums
|
==== Mapping enums
|
||||||
|
@ -276,7 +408,7 @@ The original JPA-compliant way to map enums was via the `@Enumerated` and `@MapK
|
||||||
|
|
||||||
.`@Enumerated(ORDINAL)` example
|
.`@Enumerated(ORDINAL)` example
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
include::{extrasdir}/basic/EnumeratedOrdinal.java[]
|
include::{extrasdir}/basic/EnumeratedOrdinal.java[]
|
||||||
----
|
----
|
||||||
|
@ -290,7 +422,7 @@ In the ORDINAL example, the gender column is defined as an (nullable) INTEGER ty
|
||||||
|
|
||||||
.`@Enumerated(STRING)` example
|
.`@Enumerated(STRING)` example
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
include::{extrasdir}/basic/EnumeratedString.java[]
|
include::{extrasdir}/basic/EnumeratedString.java[]
|
||||||
----
|
----
|
||||||
|
@ -310,7 +442,7 @@ Let's revisit the Gender enum example, but instead we want to store the more sta
|
||||||
|
|
||||||
.Enum mapping with AttributeConverter example
|
.Enum mapping with AttributeConverter example
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
include::{extrasdir}/basic/EnumAttributeConverter.java[]
|
include::{extrasdir}/basic/EnumAttributeConverter.java[]
|
||||||
----
|
----
|
||||||
|
@ -334,7 +466,7 @@ Let's again revisit the Gender enum example, this time using a custom Type to st
|
||||||
|
|
||||||
.Enum mapping with custom Type example
|
.Enum mapping with custom Type example
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
include::{extrasdir}/basic/EnumCustomType.java[]
|
include::{extrasdir}/basic/EnumCustomType.java[]
|
||||||
----
|
----
|
||||||
|
@ -346,7 +478,7 @@ Again, the gender column is defined as a CHAR type and would hold:
|
||||||
* `'M'` - MALE
|
* `'M'` - MALE
|
||||||
* `'F'` - FEMALE
|
* `'F'` - FEMALE
|
||||||
|
|
||||||
For additional details on using custom types, see <<basic-custom>> section..
|
For additional details on using custom types, see <<basic-custom-type>> section..
|
||||||
|
|
||||||
[[basic-lob]]
|
[[basic-lob]]
|
||||||
==== Mapping LOBs
|
==== Mapping LOBs
|
||||||
|
@ -385,7 +517,7 @@ Let's first map this using the JDBC locator.
|
||||||
|
|
||||||
.CLOB - locator mapping
|
.CLOB - locator mapping
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
include::{extrasdir}/basic/ClobLocator.java[]
|
include::{extrasdir}/basic/ClobLocator.java[]
|
||||||
----
|
----
|
||||||
|
@ -395,7 +527,7 @@ We could also map a materialized form.
|
||||||
|
|
||||||
.CLOB - materialized mapping
|
.CLOB - materialized mapping
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
include::{extrasdir}/basic/ClobMaterialized.java[]
|
include::{extrasdir}/basic/ClobMaterialized.java[]
|
||||||
----
|
----
|
||||||
|
@ -413,7 +545,7 @@ We might even want the materialized data as a char array (for some crazy reason)
|
||||||
|
|
||||||
.CLOB - materialized char[] mapping
|
.CLOB - materialized char[] mapping
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
include::{extrasdir}/basic/ClobMaterializedCharArray.java[]
|
include::{extrasdir}/basic/ClobMaterializedCharArray.java[]
|
||||||
----
|
----
|
||||||
|
@ -433,7 +565,7 @@ Let's first map this using the JDBC locator.
|
||||||
|
|
||||||
.BLOB - locator mapping
|
.BLOB - locator mapping
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
include::{extrasdir}/basic/BlobLocator.java[]
|
include::{extrasdir}/basic/BlobLocator.java[]
|
||||||
----
|
----
|
||||||
|
@ -443,7 +575,7 @@ We could also map a materialized BLOB form.
|
||||||
|
|
||||||
.BLOB - materialized mapping
|
.BLOB - materialized mapping
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
include::{extrasdir}/basic/BlobMaterialized.java[]
|
include::{extrasdir}/basic/BlobMaterialized.java[]
|
||||||
----
|
----
|
||||||
|
@ -464,7 +596,7 @@ To map a specific attribute to a nationalized variant data type, Hibernate defin
|
||||||
|
|
||||||
.NVARCHAR mapping
|
.NVARCHAR mapping
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
include::{extrasdir}/basic/NVARCHAR.java[]
|
include::{extrasdir}/basic/NVARCHAR.java[]
|
||||||
----
|
----
|
||||||
|
@ -472,7 +604,7 @@ include::{extrasdir}/basic/NVARCHAR.java[]
|
||||||
|
|
||||||
.NCLOB (locator) mapping
|
.NCLOB (locator) mapping
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
include::{extrasdir}/basic/NCLOB_locator.java[]
|
include::{extrasdir}/basic/NCLOB_locator.java[]
|
||||||
----
|
----
|
||||||
|
@ -480,7 +612,7 @@ include::{extrasdir}/basic/NCLOB_locator.java[]
|
||||||
|
|
||||||
.NCLOB (materialized) mapping
|
.NCLOB (materialized) mapping
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
include::{extrasdir}/basic/NCLOB_materialized.java[]
|
include::{extrasdir}/basic/NCLOB_materialized.java[]
|
||||||
----
|
----
|
||||||
|
@ -551,7 +683,7 @@ Considering the following entity:
|
||||||
|
|
||||||
.`java.util.Date` mapping
|
.`java.util.Date` mapping
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
include::{extrasdir}/basic/DateTemporal.java[]
|
include::{extrasdir}/basic/DateTemporal.java[]
|
||||||
----
|
----
|
||||||
|
@ -560,7 +692,7 @@ include::{extrasdir}/basic/DateTemporal.java[]
|
||||||
When persisting such entity:
|
When persisting such entity:
|
||||||
|
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
DateEvent dateEvent = new DateEvent(new Date());
|
DateEvent dateEvent = new DateEvent(new Date());
|
||||||
entityManager.persist(dateEvent);
|
entityManager.persist(dateEvent);
|
||||||
|
@ -583,7 +715,7 @@ Only the year, month and the day field were saved into the the database.
|
||||||
If we change the `@Temporal` type to TIME:
|
If we change the `@Temporal` type to TIME:
|
||||||
|
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
@Temporal(TemporalType.TIME)
|
@Temporal(TemporalType.TIME)
|
||||||
private Date timestamp;
|
private Date timestamp;
|
||||||
|
@ -604,7 +736,7 @@ VALUES ( '16:51:58', 1 )
|
||||||
When the the `@Temporal` type is set to TIMESTAMP:
|
When the the `@Temporal` type is set to TIMESTAMP:
|
||||||
|
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
@Temporal(TemporalType.TIMESTAMP)
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
private Date timestamp;
|
private Date timestamp;
|
||||||
|
@ -665,7 +797,7 @@ org.hibernate.AnnotationException: @Temporal should only be set on a java.util.D
|
||||||
[[basic-jpa-convert]]
|
[[basic-jpa-convert]]
|
||||||
==== JPA 2.1 AttributeConverters
|
==== JPA 2.1 AttributeConverters
|
||||||
|
|
||||||
Although Hibernate has long been offering <<basic-custom,custom types>>, as a JPA 2.1 provider,
|
Although Hibernate has long been offering <<basic-custom-type,custom types>>, as a JPA 2.1 provider,
|
||||||
it also supports `AttributeConverter`s as well.
|
it also supports `AttributeConverter`s as well.
|
||||||
|
|
||||||
With a custom `AttributeConverter`, the application developer can map a given JDBC type to an entity basic type.
|
With a custom `AttributeConverter`, the application developer can map a given JDBC type to an entity basic type.
|
||||||
|
@ -674,7 +806,7 @@ In the following example, the `java.util.Period` is going to be mapped to a `VAR
|
||||||
|
|
||||||
.`java.util.Period` custom `AttributeConverter`
|
.`java.util.Period` custom `AttributeConverter`
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
include::{extrasdir}/basic/PeriodStringConverter.java[]
|
include::{extrasdir}/basic/PeriodStringConverter.java[]
|
||||||
----
|
----
|
||||||
|
@ -684,7 +816,7 @@ To make use of this custom converter, the `@Convert` annotation must decorate th
|
||||||
|
|
||||||
.Entity using the custom `AttributeConverter`
|
.Entity using the custom `AttributeConverter`
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
include::{extrasdir}/basic/PeriodStringConvert.java[]
|
include::{extrasdir}/basic/PeriodStringConvert.java[]
|
||||||
----
|
----
|
||||||
|
@ -709,7 +841,7 @@ This is usually double quotes, but the SQL Server uses brackets and MySQL uses b
|
||||||
|
|
||||||
.Quoting column names
|
.Quoting column names
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
@Entity @Table(name="`Line Item`")
|
@Entity @Table(name="`Line Item`")
|
||||||
class LineItem {
|
class LineItem {
|
||||||
|
@ -811,7 +943,7 @@ For example, if your database provides a set of data encryption functions, you c
|
||||||
|
|
||||||
.`@ColumnTransformer` example
|
.`@ColumnTransformer` example
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
@Entity
|
@Entity
|
||||||
class CreditCard {
|
class CreditCard {
|
||||||
|
@ -838,7 +970,7 @@ If a property uses more than one column, you must use the `forColumn` attribute
|
||||||
|
|
||||||
.`@ColumnTransformer` `forColumn` attribute usage
|
.`@ColumnTransformer` `forColumn` attribute usage
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
@Entity
|
@Entity
|
||||||
class User {
|
class User {
|
||||||
|
@ -877,7 +1009,7 @@ You can use a SQL fragment (aka formula) instead of mapping a property into a co
|
||||||
|
|
||||||
.`@Formula` mapping usage
|
.`@Formula` mapping usage
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
@Formula("obj_length * obj_height * obj_width")
|
@Formula("obj_length * obj_height * obj_width")
|
||||||
private long objectVolume;
|
private long objectVolume;
|
||||||
|
@ -911,7 +1043,7 @@ You must specify the mapping from values of the metaType to class names.
|
||||||
|
|
||||||
.`@Any` mapping usage
|
.`@Any` mapping usage
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
@Any(
|
@Any(
|
||||||
metaColumn = @Column( name = "property_type" ),
|
metaColumn = @Column( name = "property_type" ),
|
||||||
|
@ -934,7 +1066,7 @@ Note that `@AnyDef` can be mutualized and reused. It is recommended to place it
|
||||||
|
|
||||||
.`@AnyMetaDef` mapping usage
|
.`@AnyMetaDef` mapping usage
|
||||||
====
|
====
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
//on a package
|
//on a package
|
||||||
@AnyMetaDef( name="property"
|
@AnyMetaDef( name="property"
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
@Entity
|
|
||||||
public class Product {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@Basic
|
|
||||||
private Integer id;
|
|
||||||
|
|
||||||
@Basic
|
|
||||||
private String sku;
|
|
||||||
|
|
||||||
@Basic
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@Basic
|
|
||||||
@Column( name = "NOTES" )
|
|
||||||
private String description;
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
public class FizzywigType1 implements org.hibernate.type.BasicType {
|
|
||||||
public static final FizzywigType1 INSTANCE = new FizzywigType1();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getRegistrationKeys() {
|
|
||||||
return new String[]{Fizzywig.class.getName()};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int[] sqlTypes( Mapping mapping ) {
|
|
||||||
return new int[]{java.sql.Types.VARCHAR};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class getReturnedClass() {
|
|
||||||
return Money.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object nullSafeGet(
|
|
||||||
ResultSet rs,
|
|
||||||
String[] names,
|
|
||||||
SessionImplementor session,
|
|
||||||
Object owner) throws SQLException {
|
|
||||||
return Fizzwig.fromString(
|
|
||||||
StringType.INSTANCE.get( rs, names[0], sesson )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void nullSafeSet(
|
|
||||||
PreparedStatement st,
|
|
||||||
Object value,
|
|
||||||
int index,
|
|
||||||
boolean[] settable,
|
|
||||||
SessionImplementor session) throws SQLException {
|
|
||||||
final String dbValue = value == null
|
|
||||||
? null
|
|
||||||
: (( Fizzywig ) value).asString();
|
|
||||||
StringType.INSTANCE.nullSafeSet( st, value, index, settable, session );
|
|
||||||
}
|
|
||||||
|
|
||||||
...
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
MetadataSources metadataSources = ...;
|
|
||||||
metadataSources.getMetaDataBuilder().applyBasicType( FizzwigType1.INSTANCE );
|
|
||||||
...
|
|
|
@ -1,40 +0,0 @@
|
||||||
public class FizzywigType2 implements org.hibernate.usertype.UserType {
|
|
||||||
|
|
||||||
public static final String KEYS = new String[]{Fizzywig.class.getName()};
|
|
||||||
public static final FizzywigType1 INSTANCE = new FizzywigType1();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int[] sqlTypes( Mapping mapping ) {
|
|
||||||
return new int[]{java.sql.Types.VARCHAR};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class getReturnedClass() {
|
|
||||||
return Fizzywig.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object nullSafeGet(
|
|
||||||
ResultSet rs,
|
|
||||||
String[] names,
|
|
||||||
SessionImplementor session,
|
|
||||||
Object owner) throws SQLException {
|
|
||||||
return Fizzwig.fromString(
|
|
||||||
StringType.INSTANCE.get( rs, names[0], sesson )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void nullSafeSet(
|
|
||||||
PreparedStatement st,
|
|
||||||
Object value,
|
|
||||||
int index,
|
|
||||||
SessionImplementor session) throws SQLException {
|
|
||||||
final String dbValue = value == null
|
|
||||||
? null
|
|
||||||
: (( Fizzywig ) value).asString();
|
|
||||||
StringType.INSTANCE.nullSafeSet( st, value, index, session );
|
|
||||||
}
|
|
||||||
|
|
||||||
...
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
MetadataSources metadataSources = ...;
|
|
||||||
metadataSources.getMetaDataBuilder().applyBasicType( FizzwigType2.KEYS,FizzwigType2.INSTANCE )
|
|
||||||
...
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
DEBUG SQL:92 -
|
||||||
|
insert
|
||||||
|
into
|
||||||
|
Product
|
||||||
|
(bitSet, id)
|
||||||
|
values
|
||||||
|
(?, ?)
|
||||||
|
|
||||||
|
TRACE BasicBinder:65 - binding parameter [1] as [VARCHAR] - [{0, 65, 128, 129}]
|
||||||
|
TRACE BasicBinder:65 - binding parameter [2] as [INTEGER] - [1]
|
||||||
|
|
||||||
|
DEBUG SQL:92 -
|
||||||
|
select
|
||||||
|
bitsettype0_.id as id1_0_0_,
|
||||||
|
bitsettype0_.bitSet as bitSet2_0_0_
|
||||||
|
from
|
||||||
|
Product bitsettype0_
|
||||||
|
where
|
||||||
|
bitsettype0_.id=?
|
||||||
|
|
||||||
|
TRACE BasicBinder:65 - binding parameter [1] as [INTEGER] - [1]
|
||||||
|
TRACE BasicExtractor:61 - extracted value ([bitSet2_0_0_] : [VARCHAR]) - [{0, 65, 128, 129}]
|
|
@ -0,0 +1,22 @@
|
||||||
|
DEBUG SQL:92 -
|
||||||
|
insert
|
||||||
|
into
|
||||||
|
Product
|
||||||
|
(bitSet, id)
|
||||||
|
values
|
||||||
|
(?, ?)
|
||||||
|
|
||||||
|
DEBUG BitSetUserType:71 - Binding 1,10,11 to parameter 1
|
||||||
|
TRACE BasicBinder:65 - binding parameter [2] as [INTEGER] - [1]
|
||||||
|
|
||||||
|
DEBUG SQL:92 -
|
||||||
|
select
|
||||||
|
bitsetuser0_.id as id1_0_0_,
|
||||||
|
bitsetuser0_.bitSet as bitSet2_0_0_
|
||||||
|
from
|
||||||
|
Product bitsetuser0_
|
||||||
|
where
|
||||||
|
bitsetuser0_.id=?
|
||||||
|
|
||||||
|
TRACE BasicBinder:65 - binding parameter [1] as [INTEGER] - [1]
|
||||||
|
DEBUG BitSetUserType:56 - Result set column bitSet2_0_0_ value is 1,10,11
|
|
@ -1,16 +0,0 @@
|
||||||
@Entity
|
|
||||||
public class Product {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@Basic
|
|
||||||
private Integer id;
|
|
||||||
|
|
||||||
@Basic
|
|
||||||
private String sku;
|
|
||||||
|
|
||||||
@Basic
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@Basic
|
|
||||||
private String description;
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
@Entity
|
|
||||||
public class Product {
|
|
||||||
@Id
|
|
||||||
private Integer id;
|
|
||||||
private String sku;
|
|
||||||
private String name;
|
|
||||||
private String description;
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
@org.hibernate.annotations.Type( type = "nstring" )
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@org.hibernate.annotations.Type( type = "materialized_nclob" )
|
|
||||||
private String description;
|
|
|
@ -1,17 +0,0 @@
|
||||||
public class Contact {
|
|
||||||
private Integer id;
|
|
||||||
private Name name;
|
|
||||||
private String notes;
|
|
||||||
private URL website;
|
|
||||||
private boolean starred;
|
|
||||||
|
|
||||||
// getters and setters ommitted
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Name {
|
|
||||||
private String first;
|
|
||||||
private String middle;
|
|
||||||
private String last;
|
|
||||||
|
|
||||||
// getters and setters ommitted
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
create table Contact (
|
|
||||||
id INTEGER NOT NULL,
|
|
||||||
first_name VARCHAR,
|
|
||||||
middle_name VARCHAR,
|
|
||||||
last_name VARCHAR,
|
|
||||||
notes VARCHAR,
|
|
||||||
starred BIT,
|
|
||||||
website VARCHAR
|
|
||||||
)
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
create table Contact (
|
||||||
|
id integer not null,
|
||||||
|
first varchar(255),
|
||||||
|
last varchar(255),
|
||||||
|
middle varchar(255),
|
||||||
|
notes varchar(255),
|
||||||
|
starred boolean not null,
|
||||||
|
website varchar(255),
|
||||||
|
primary key (id)
|
||||||
|
)
|
|
@ -1,6 +1,7 @@
|
||||||
[[mapping_types]]
|
[[mapping-types]]
|
||||||
=== Mapping types
|
=== Mapping types
|
||||||
:sourcedir: extras
|
:sourcedir: ../../../../../test/java/org/hibernate/userguide/mapping
|
||||||
|
:extrasdir: extras/types
|
||||||
|
|
||||||
Hibernate understands both the Java and JDBC representations of application data.
|
Hibernate understands both the Java and JDBC representations of application data.
|
||||||
The ability to read/write this data from/to the database is the function of a Hibernate _type_.
|
The ability to read/write this data from/to the database is the function of a Hibernate _type_.
|
||||||
|
@ -10,7 +11,6 @@ This Hibernate type also describes various aspects of behavior of the Java type
|
||||||
.Usage of the word _type_
|
.Usage of the word _type_
|
||||||
[NOTE]
|
[NOTE]
|
||||||
====
|
====
|
||||||
|
|
||||||
The Hibernate type is neither a Java type nor a SQL data type.
|
The Hibernate type is neither a Java type nor a SQL data type.
|
||||||
It provides information about both of these as well as understanding marshalling between.
|
It provides information about both of these as well as understanding marshalling between.
|
||||||
|
|
||||||
|
@ -19,16 +19,17 @@ When you encounter the term type in discussions of Hibernate, it may refer to th
|
||||||
|
|
||||||
To help understand the type categorizations, let's look at a simple table and domain model that we wish to map.
|
To help understand the type categorizations, let's look at a simple table and domain model that we wish to map.
|
||||||
|
|
||||||
|
[[mapping-types-basic-example]]
|
||||||
.Simple table and domain model
|
.Simple table and domain model
|
||||||
====
|
====
|
||||||
[source,sql]
|
[source, SQL, indent=0]
|
||||||
----
|
----
|
||||||
include::{sourcedir}/mapping_types/Contact.sql[]
|
include::{extrasdir}/mapping-types-basic-example.sql[]
|
||||||
----
|
----
|
||||||
|
|
||||||
[source,java]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
include::{sourcedir}/mapping_types/Contact.java[]
|
include::{sourcedir}/basic/TypeCategoryTest.java[tags=mapping-types-basic-example]
|
||||||
----
|
----
|
||||||
====
|
====
|
||||||
|
|
|
@ -53,6 +53,8 @@ import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
|
||||||
import org.hibernate.jpa.boot.internal.PersistenceUnitInfoDescriptor;
|
import org.hibernate.jpa.boot.internal.PersistenceUnitInfoDescriptor;
|
||||||
import org.hibernate.service.ServiceRegistry;
|
import org.hibernate.service.ServiceRegistry;
|
||||||
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
|
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
|
||||||
|
import org.hibernate.userguide.mapping.basic.BitSetType;
|
||||||
|
import org.hibernate.userguide.mapping.basic.BitSetUserType;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -507,4 +509,42 @@ public class BootstrapTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//end::bootstrap-native-PersistenceUnitInfoImpl-example[]
|
//end::bootstrap-native-PersistenceUnitInfoImpl-example[]
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_basic_custom_type_register_BasicType_example() {
|
||||||
|
try {
|
||||||
|
//tag::basic-custom-type-register-BasicType-example[]
|
||||||
|
ServiceRegistry standardRegistry =
|
||||||
|
new StandardServiceRegistryBuilder().build();
|
||||||
|
|
||||||
|
MetadataSources sources = new MetadataSources( standardRegistry );
|
||||||
|
|
||||||
|
MetadataBuilder metadataBuilder = sources.getMetadataBuilder();
|
||||||
|
|
||||||
|
metadataBuilder.applyBasicType( BitSetType.INSTANCE );
|
||||||
|
//end::basic-custom-type-register-BasicType-example[]
|
||||||
|
}
|
||||||
|
catch (Exception ignore) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_basic_custom_type_register_UserType_example() {
|
||||||
|
try {
|
||||||
|
//tag::basic-custom-type-register-UserType-example[]
|
||||||
|
ServiceRegistry standardRegistry =
|
||||||
|
new StandardServiceRegistryBuilder().build();
|
||||||
|
|
||||||
|
MetadataSources sources = new MetadataSources( standardRegistry );
|
||||||
|
|
||||||
|
MetadataBuilder metadataBuilder = sources.getMetadataBuilder();
|
||||||
|
|
||||||
|
metadataBuilder.applyBasicType( BitSetUserType.INSTANCE, "bitset" );
|
||||||
|
//end::basic-custom-type-register-UserType-example[]
|
||||||
|
}
|
||||||
|
catch (Exception ignore) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
package org.hibernate.userguide.mapping.basic;
|
||||||
|
|
||||||
|
import java.util.BitSet;
|
||||||
|
|
||||||
|
import org.hibernate.dialect.Dialect;
|
||||||
|
import org.hibernate.type.AbstractSingleColumnStandardBasicType;
|
||||||
|
import org.hibernate.type.DiscriminatorType;
|
||||||
|
import org.hibernate.type.descriptor.sql.VarcharTypeDescriptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Vlad Mihalcea
|
||||||
|
*/
|
||||||
|
//tag::basic-custom-type-BitSetType-example[]
|
||||||
|
public class BitSetType
|
||||||
|
extends AbstractSingleColumnStandardBasicType<BitSet>
|
||||||
|
implements DiscriminatorType<BitSet> {
|
||||||
|
|
||||||
|
public static final BitSetType INSTANCE = new BitSetType();
|
||||||
|
|
||||||
|
public BitSetType() {
|
||||||
|
super( VarcharTypeDescriptor.INSTANCE, BitSetTypeDescriptor.INSTANCE );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BitSet stringToObject(String xml) throws Exception {
|
||||||
|
return fromString( xml );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String objectToSQLString(BitSet value, Dialect dialect) throws Exception {
|
||||||
|
return toString( value );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "bitset";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
//end::basic-custom-type-BitSetType-example[]
|
|
@ -0,0 +1,75 @@
|
||||||
|
package org.hibernate.userguide.mapping.basic;
|
||||||
|
|
||||||
|
import java.util.BitSet;
|
||||||
|
|
||||||
|
import org.hibernate.type.descriptor.WrapperOptions;
|
||||||
|
import org.hibernate.type.descriptor.java.AbstractTypeDescriptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Vlad Mihalcea
|
||||||
|
*/
|
||||||
|
//tag::basic-custom-type-BitSetTypeDescriptor-example[]
|
||||||
|
public class BitSetTypeDescriptor extends AbstractTypeDescriptor<BitSet> {
|
||||||
|
|
||||||
|
private static final String DELIMITER = ",";
|
||||||
|
|
||||||
|
public static final BitSetTypeDescriptor INSTANCE = new BitSetTypeDescriptor();
|
||||||
|
|
||||||
|
public BitSetTypeDescriptor() {
|
||||||
|
super( BitSet.class );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(BitSet value) {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
for ( long token : value.toLongArray() ) {
|
||||||
|
if ( builder.length() > 0 ) {
|
||||||
|
builder.append( DELIMITER );
|
||||||
|
}
|
||||||
|
builder.append( Long.toString( token, 2 ) );
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BitSet fromString(String string) {
|
||||||
|
if ( string == null || string.isEmpty() ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String[] tokens = string.split( DELIMITER );
|
||||||
|
long[] values = new long[tokens.length];
|
||||||
|
|
||||||
|
for ( int i = 0; i < tokens.length; i++ ) {
|
||||||
|
values[i] = Long.valueOf( tokens[i], 2 );
|
||||||
|
}
|
||||||
|
return BitSet.valueOf( values );
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"unchecked"})
|
||||||
|
public <X> X unwrap(BitSet value, Class<X> type, WrapperOptions options) {
|
||||||
|
if ( value == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if ( BitSet.class.isAssignableFrom( type ) ) {
|
||||||
|
return (X) value;
|
||||||
|
}
|
||||||
|
if ( String.class.isAssignableFrom( type ) ) {
|
||||||
|
return (X) toString( value);
|
||||||
|
}
|
||||||
|
throw unknownUnwrap( type );
|
||||||
|
}
|
||||||
|
|
||||||
|
public <X> BitSet wrap(X value, WrapperOptions options) {
|
||||||
|
if ( value == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if ( String.class.isInstance( value ) ) {
|
||||||
|
return fromString( (String) value );
|
||||||
|
}
|
||||||
|
if ( BitSet.class.isInstance( value ) ) {
|
||||||
|
return (BitSet) value;
|
||||||
|
}
|
||||||
|
throw unknownWrap( value.getClass() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//end::basic-custom-type-BitSetTypeDescriptor-example[]
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
* 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.userguide.mapping.basic;
|
||||||
|
|
||||||
|
import java.util.BitSet;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Type;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hibernate.userguide.util.TransactionUtil.doInHibernate;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Vlad Mihalcea
|
||||||
|
*/
|
||||||
|
public class BitSetTypeTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class<?>[] {
|
||||||
|
Product.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Configuration constructAndConfigureConfiguration() {
|
||||||
|
Configuration configuration = super.constructAndConfigureConfiguration();
|
||||||
|
//tag::basic-custom-type-register-BasicType-example[]
|
||||||
|
configuration.registerTypeContributor( (typeContributions, serviceRegistry) -> {
|
||||||
|
typeContributions.contributeType( BitSetType.INSTANCE );
|
||||||
|
} );
|
||||||
|
//end::basic-custom-type-register-BasicType-example[]
|
||||||
|
return configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
|
||||||
|
//tag::basic-custom-type-BitSetType-persistence-example[]
|
||||||
|
BitSet bitSet = BitSet.valueOf( new long[] {1, 2, 3} );
|
||||||
|
|
||||||
|
doInHibernate( this::sessionFactory, session -> {
|
||||||
|
Product product = new Product( );
|
||||||
|
product.setId( 1 );
|
||||||
|
product.setBitSet( bitSet );
|
||||||
|
session.persist( product );
|
||||||
|
} );
|
||||||
|
|
||||||
|
doInHibernate( this::sessionFactory, session -> {
|
||||||
|
Product product = session.get( Product.class, 1 );
|
||||||
|
assertEquals(bitSet, product.getBitSet());
|
||||||
|
} );
|
||||||
|
//end::basic-custom-type-BitSetType-persistence-example[]
|
||||||
|
}
|
||||||
|
|
||||||
|
//tag::basic-custom-type-BitSetType-mapping-example[]
|
||||||
|
@Entity(name = "Product")
|
||||||
|
public static class Product {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@Type( type = "bitset" )
|
||||||
|
private BitSet bitSet;
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BitSet getBitSet() {
|
||||||
|
return bitSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBitSet(BitSet bitSet) {
|
||||||
|
this.bitSet = bitSet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//end::basic-custom-type-BitSetType-mapping-example[]
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
package org.hibernate.userguide.mapping.basic;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Types;
|
||||||
|
import java.util.BitSet;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
import org.hibernate.type.StringType;
|
||||||
|
import org.hibernate.usertype.UserType;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Vlad Mihalcea
|
||||||
|
*/
|
||||||
|
//tag::basic-custom-type-BitSetUserType-example[]
|
||||||
|
public class BitSetUserType implements UserType {
|
||||||
|
|
||||||
|
public static final BitSetUserType INSTANCE = new BitSetUserType();
|
||||||
|
|
||||||
|
private static final Logger log = Logger.getLogger( BitSetUserType.class );
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[] sqlTypes() {
|
||||||
|
return new int[] {StringType.INSTANCE.sqlType()};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class returnedClass() {
|
||||||
|
return String.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object x, Object y)
|
||||||
|
throws HibernateException {
|
||||||
|
return Objects.equals( x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode(Object x)
|
||||||
|
throws HibernateException {
|
||||||
|
return Objects.hashCode( x );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object nullSafeGet(
|
||||||
|
ResultSet rs, String[] names, SessionImplementor session, Object owner)
|
||||||
|
throws HibernateException, SQLException {
|
||||||
|
String columnName = names[0];
|
||||||
|
String columnValue = (String) rs.getObject( columnName );
|
||||||
|
log.debugv("Result set column {0} value is {1}", columnName, columnValue);
|
||||||
|
return columnValue == null ? null :
|
||||||
|
BitSetTypeDescriptor.INSTANCE.fromString( columnValue );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nullSafeSet(
|
||||||
|
PreparedStatement st, Object value, int index, SessionImplementor session)
|
||||||
|
throws HibernateException, SQLException {
|
||||||
|
if ( value == null ) {
|
||||||
|
log.debugv("Binding null to parameter {0} ",index);
|
||||||
|
st.setNull( index, Types.VARCHAR );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
String stringValue = BitSetTypeDescriptor.INSTANCE.toString( (BitSet) value );
|
||||||
|
log.debugv("Binding {0} to parameter {1} ", stringValue, index);
|
||||||
|
st.setString( index, stringValue );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object deepCopy(Object value)
|
||||||
|
throws HibernateException {
|
||||||
|
return value == null ? null :
|
||||||
|
BitSet.valueOf( BitSet.class.cast( value ).toLongArray() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMutable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Serializable disassemble(Object value)
|
||||||
|
throws HibernateException {
|
||||||
|
return (BitSet) deepCopy( value );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object assemble(Serializable cached, Object owner)
|
||||||
|
throws HibernateException {
|
||||||
|
return deepCopy( cached );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object replace(Object original, Object target, Object owner)
|
||||||
|
throws HibernateException {
|
||||||
|
return deepCopy( original );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//end::basic-custom-type-BitSetUserType-example[]
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* 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.userguide.mapping.basic;
|
||||||
|
|
||||||
|
import java.util.BitSet;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Type;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hibernate.userguide.util.TransactionUtil.doInHibernate;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Vlad Mihalcea
|
||||||
|
*/
|
||||||
|
public class BitSetUserTypeTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class<?>[] {
|
||||||
|
Product.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Configuration constructAndConfigureConfiguration() {
|
||||||
|
Configuration configuration = super.constructAndConfigureConfiguration();
|
||||||
|
//tag::basic-custom-type-register-UserType-example[]
|
||||||
|
configuration.registerTypeContributor( (typeContributions, serviceRegistry) -> {
|
||||||
|
typeContributions.contributeType( BitSetUserType.INSTANCE, "bitset");
|
||||||
|
} );
|
||||||
|
//end::basic-custom-type-register-UserType-example[]
|
||||||
|
return configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
|
||||||
|
BitSet bitSet = BitSet.valueOf( new long[] {1, 2, 3} );
|
||||||
|
|
||||||
|
doInHibernate( this::sessionFactory, session -> {
|
||||||
|
Product product = new Product( );
|
||||||
|
product.setId( 1 );
|
||||||
|
product.setBitSet( bitSet );
|
||||||
|
session.persist( product );
|
||||||
|
} );
|
||||||
|
|
||||||
|
doInHibernate( this::sessionFactory, session -> {
|
||||||
|
Product product = session.get( Product.class, 1 );
|
||||||
|
assertEquals(bitSet, product.getBitSet());
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
//tag::basic-custom-type-BitSetUserType-mapping-example[]
|
||||||
|
@Entity(name = "Product")
|
||||||
|
public static class Product {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@Type( type = "bitset" )
|
||||||
|
private BitSet bitSet;
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BitSet getBitSet() {
|
||||||
|
return bitSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBitSet(BitSet bitSet) {
|
||||||
|
this.bitSet = bitSet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//end::basic-custom-type-BitSetUserType-mapping-example[]
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* 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.userguide.mapping.basic;
|
||||||
|
|
||||||
|
import javax.persistence.Basic;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hibernate.userguide.util.TransactionUtil.doInJPA;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Vlad Mihalcea
|
||||||
|
*/
|
||||||
|
public class ExplicitBasicTypeTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class<?>[] {
|
||||||
|
Product.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
Product product = new Product( );
|
||||||
|
product.id = 1;
|
||||||
|
entityManager.persist( product );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
//tag::basic-annotation-explicit-example[]
|
||||||
|
@Entity(name = "Product")
|
||||||
|
public class Product {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@Basic
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@Basic
|
||||||
|
private String sku;
|
||||||
|
|
||||||
|
@Basic
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Basic
|
||||||
|
private String description;
|
||||||
|
}
|
||||||
|
//end::basic-annotation-explicit-example[]
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* 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.userguide.mapping.basic;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hibernate.userguide.util.TransactionUtil.doInJPA;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Vlad Mihalcea
|
||||||
|
*/
|
||||||
|
public class ExplicitColumnNamingTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class<?>[] {
|
||||||
|
Product.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
Product product = new Product( );
|
||||||
|
product.id = 1;
|
||||||
|
entityManager.persist( product );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
//tag::basic-annotation-explicit-column-example[]
|
||||||
|
@Entity(name = "Product")
|
||||||
|
public class Product {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private String sku;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Column( name = "NOTES" )
|
||||||
|
private String description;
|
||||||
|
}
|
||||||
|
//end::basic-annotation-explicit-column-example[]
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* 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.userguide.mapping.basic;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hibernate.userguide.util.TransactionUtil.doInJPA;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Vlad Mihalcea
|
||||||
|
*/
|
||||||
|
public class ExplicitTypeTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class<?>[] {
|
||||||
|
Product.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
//tag::basic-type-annotation-example[]
|
||||||
|
@Entity(name = "Product")
|
||||||
|
public class Product {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private String sku;
|
||||||
|
|
||||||
|
@org.hibernate.annotations.Type( type = "nstring" )
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@org.hibernate.annotations.Type( type = "materialized_nclob" )
|
||||||
|
private String description;
|
||||||
|
}
|
||||||
|
//end::basic-type-annotation-example[]
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* 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.userguide.mapping.basic;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hibernate.userguide.util.TransactionUtil.doInJPA;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Vlad Mihalcea
|
||||||
|
*/
|
||||||
|
public class ImplicitBasicTypeTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class<?>[] {
|
||||||
|
Product.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
Product product = new Product( );
|
||||||
|
product.id = 1;
|
||||||
|
entityManager.persist( product );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
//tag::basic-annotation-implicit-example[]
|
||||||
|
@Entity(name = "Product")
|
||||||
|
public class Product {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private String sku;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
}
|
||||||
|
//end::basic-annotation-implicit-example[]
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* 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.userguide.mapping.basic;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import javax.persistence.Embeddable;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hibernate.userguide.util.TransactionUtil.doInJPA;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Vlad Mihalcea
|
||||||
|
*/
|
||||||
|
public class TypeCategoryTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class<?>[] {
|
||||||
|
Contact.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
Contact contact = new Contact( );
|
||||||
|
contact.id = 1;
|
||||||
|
entityManager.persist( contact );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
//tag::mapping-types-basic-example[]
|
||||||
|
@Entity(name = "Contact")
|
||||||
|
public static class Contact {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private Name name;
|
||||||
|
|
||||||
|
private String notes;
|
||||||
|
|
||||||
|
private URL website;
|
||||||
|
|
||||||
|
private boolean starred;
|
||||||
|
|
||||||
|
// getters and setters omitted
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
public class Name {
|
||||||
|
|
||||||
|
private String first;
|
||||||
|
|
||||||
|
private String middle;
|
||||||
|
|
||||||
|
private String last;
|
||||||
|
|
||||||
|
// getters and setters omitted
|
||||||
|
}
|
||||||
|
//end::mapping-types-basic-example[]
|
||||||
|
}
|
Loading…
Reference in New Issue