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.
|
||||
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::basic_types.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.
|
||||
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.
|
||||
See the <chapters/pc/BytecodeEnhancement.adoc#BytecodeEnhancement,BytecodeEnhancement>> for additional information on fetching and on bytecode enhancement.
|
||||
|
||||
[[basic-column-annotation]]
|
||||
==== The `@Column` annotation
|
||||
|
||||
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.
|
||||
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
|
||||
====
|
||||
[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.
|
||||
|
||||
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.
|
||||
|
||||
[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
|
||||
`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
|
||||
|
||||
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.
|
||||
|
||||
[[basic-type-annotation-example]]
|
||||
.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
|
||||
* 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
|
||||
|
||||
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.
|
||||
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.
|
||||
There are two approaches to developing a custom type:
|
||||
|
||||
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[]
|
||||
----
|
||||
|
||||
[source,java]
|
||||
----
|
||||
include::{extrasdir}/basic/FizzywigType2_reg.java[]
|
||||
include::{sourcedir}/basic/BitSetTypeDescriptor.java[tags=basic-custom-type-BitSetTypeDescriptor-example]
|
||||
----
|
||||
====
|
||||
|
||||
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]]
|
||||
==== Mapping enums
|
||||
|
@ -276,7 +408,7 @@ The original JPA-compliant way to map enums was via the `@Enumerated` and `@MapK
|
|||
|
||||
.`@Enumerated(ORDINAL)` example
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
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
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
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
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
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
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{extrasdir}/basic/EnumCustomType.java[]
|
||||
----
|
||||
|
@ -346,7 +478,7 @@ Again, the gender column is defined as a CHAR type and would hold:
|
|||
* `'M'` - MALE
|
||||
* `'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]]
|
||||
==== Mapping LOBs
|
||||
|
@ -385,7 +517,7 @@ Let's first map this using the JDBC locator.
|
|||
|
||||
.CLOB - locator mapping
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{extrasdir}/basic/ClobLocator.java[]
|
||||
----
|
||||
|
@ -395,7 +527,7 @@ We could also map a materialized form.
|
|||
|
||||
.CLOB - materialized mapping
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
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
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{extrasdir}/basic/ClobMaterializedCharArray.java[]
|
||||
----
|
||||
|
@ -433,7 +565,7 @@ Let's first map this using the JDBC locator.
|
|||
|
||||
.BLOB - locator mapping
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{extrasdir}/basic/BlobLocator.java[]
|
||||
----
|
||||
|
@ -443,7 +575,7 @@ We could also map a materialized BLOB form.
|
|||
|
||||
.BLOB - materialized mapping
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{extrasdir}/basic/BlobMaterialized.java[]
|
||||
----
|
||||
|
@ -464,7 +596,7 @@ To map a specific attribute to a nationalized variant data type, Hibernate defin
|
|||
|
||||
.NVARCHAR mapping
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{extrasdir}/basic/NVARCHAR.java[]
|
||||
----
|
||||
|
@ -472,7 +604,7 @@ include::{extrasdir}/basic/NVARCHAR.java[]
|
|||
|
||||
.NCLOB (locator) mapping
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{extrasdir}/basic/NCLOB_locator.java[]
|
||||
----
|
||||
|
@ -480,7 +612,7 @@ include::{extrasdir}/basic/NCLOB_locator.java[]
|
|||
|
||||
.NCLOB (materialized) mapping
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{extrasdir}/basic/NCLOB_materialized.java[]
|
||||
----
|
||||
|
@ -551,7 +683,7 @@ Considering the following entity:
|
|||
|
||||
.`java.util.Date` mapping
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{extrasdir}/basic/DateTemporal.java[]
|
||||
----
|
||||
|
@ -560,7 +692,7 @@ include::{extrasdir}/basic/DateTemporal.java[]
|
|||
When persisting such entity:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
DateEvent dateEvent = new DateEvent(new Date());
|
||||
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:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
@Temporal(TemporalType.TIME)
|
||||
private Date timestamp;
|
||||
|
@ -604,7 +736,7 @@ VALUES ( '16:51:58', 1 )
|
|||
When the the `@Temporal` type is set to TIMESTAMP:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date timestamp;
|
||||
|
@ -665,7 +797,7 @@ org.hibernate.AnnotationException: @Temporal should only be set on a java.util.D
|
|||
[[basic-jpa-convert]]
|
||||
==== 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.
|
||||
|
||||
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`
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
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`
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
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
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
@Entity @Table(name="`Line Item`")
|
||||
class LineItem {
|
||||
|
@ -811,7 +943,7 @@ For example, if your database provides a set of data encryption functions, you c
|
|||
|
||||
.`@ColumnTransformer` example
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
@Entity
|
||||
class CreditCard {
|
||||
|
@ -838,7 +970,7 @@ If a property uses more than one column, you must use the `forColumn` attribute
|
|||
|
||||
.`@ColumnTransformer` `forColumn` attribute usage
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
@Entity
|
||||
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
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
@Formula("obj_length * obj_height * obj_width")
|
||||
private long objectVolume;
|
||||
|
@ -911,7 +1043,7 @@ You must specify the mapping from values of the metaType to class names.
|
|||
|
||||
.`@Any` mapping usage
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
@Any(
|
||||
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
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
//on a package
|
||||
@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
|
||||
:sourcedir: extras
|
||||
:sourcedir: ../../../../../test/java/org/hibernate/userguide/mapping
|
||||
:extrasdir: extras/types
|
||||
|
||||
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_.
|
||||
|
@ -10,7 +11,6 @@ This Hibernate type also describes various aspects of behavior of the Java type
|
|||
.Usage of the word _type_
|
||||
[NOTE]
|
||||
====
|
||||
|
||||
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.
|
||||
|
||||
|
@ -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.
|
||||
|
||||
[[mapping-types-basic-example]]
|
||||
.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.service.ServiceRegistry;
|
||||
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
|
||||
import org.hibernate.userguide.mapping.basic.BitSetType;
|
||||
import org.hibernate.userguide.mapping.basic.BitSetUserType;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -507,4 +509,42 @@ public class BootstrapTest {
|
|||
}
|
||||
}
|
||||
//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