HHH-14589 - Make sure documentation examples regarding basic-types work and update the section

- re-enable the basic-type tests in the `documentation` module
- fix basic-type resolution in various cases from tests in both `hibernate-core` and `documentation`
- updated the basic_types.adoc user-guide section + moved much of the "legacy" discussion to an appendix
- fixed missing impls of the optional contract `org.hibernate.type.AdjustableBasicType`
- improved handling of `NationalizationSupport` offered by a Dialect

NOTE :
- changes to `ColumnTransformerTest` are related to "composite basics" not being supported, not problems with `ColumnTransformer`.
- final failure in `org.hibernate.userguide.mapping.basic` is `SubselectTest#testRefreshLifecycle` which actually fails because refresh is not working properly
This commit is contained in:
Steve Ebersole 2021-05-08 15:42:43 -05:00
parent 987dbbba2f
commit 71515af5cc
155 changed files with 7401 additions and 1667 deletions

86
design/working/fk.adoc Normal file
View File

@ -0,0 +1,86 @@
= Mapping foreign-keys
The relational model:
```
orders (
id (PK),
customer_fk,
...
)
customers (
id (PK),
...
)
FK "customer_orders" : orders.cust_fk -> customers.id
```
So we have a foreign-key between `orders` and `customers` where:
key-side:: `orders.customer_fk`
target-side:: `customers.id`
Assuming bi-directionality, we have 2 `Association` refs:
* `Order#customer` which models the key-side of the FK,
* `Customer#orders` which models the target-side
There is a single ForeignKeyDescriptor instance for this FK in our metamodel, with 2 Sides:
```
ForeignKeyDescriptor (
name : "customer_orders",
keySide (
nature: KEY,
column(s) : `orders.customer_fk`,
keyModelPart : BasicType(...),
...
),
targetSide (
nature: TARGET,
column(s) : `customer.id`,
keyModelPart : BasicType(...),
...
)
)
```
So this gives us all the information we need. We just need to model that within the `Association` contract:
```
ManyToOne (
name: `Order#customer`,
foreignKeyDescriptor : FKD(customer_orders),
side : FKD(customer_orders)#keySide
)
OneToMany (
name: `Customer#orders`,
foreignKeyDescriptor : FKD(customer_orders),
side : FKD(customer_orders)#targetSide
)
```
When rendering one of these associations into SQL, we have all of the information we need. Let's
assume we are processing HQL like `from Order join fetch customer`. We know:
1. We be "coming from" the `Order` side, meaning the LHS will be `Order` and the RHS will be `Order#customer`
2. `Order#customer` knows that it models the Side(KEY) of the FKD(customer_orders).
Further, `Order#customer` also knows that the "other side" is, well, the other Side (here, the TARGET) modeled on the FKD.
All of this allows us to properly render join predicate.
If we come from the other side: `from Customer join fetch orders`, similar situation:
1. Here we are "coming from" the Customer side, meaning the LHS will be `Customer` and RHS is `Customer#orders`.
2. `Customer#orders` knows it is the `Side(TARGET)` of the FKD(customer_orders).

View File

@ -82,6 +82,8 @@ else {
task release( dependsOn: [clean, test] )
}
//tasks.test.include 'org/hibernate/'
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// grouping tasks - declaration, see below for task dependency definitions
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -300,6 +302,10 @@ task renderIntegrationGuide(type: AsciidoctorTask, group: 'Documentation') {
// Testing
test {
include '**/mapping/basic/**'
}
// resources inherently exclude sources
sourceSets.test.resources {
setSrcDirs( ['src/test/java','src/test/resources'] )

View File

@ -4,3 +4,4 @@
- [[[PoEAA]]] Martin Fowler. https://www.martinfowler.com/books/eaa.html[Patterns of Enterprise Application Architecture].
Addison-Wesley Publishing Company. 2003.
- [[[JPwH]]] Christian Bauer & Gavin King. https://www.manning.com/books/java-persistence-with-hibernate-second-edition[Java Persistence with Hibernate, Second Edition]. Manning Publications Co. 2015.
- [[[jdbc]]] https://download.oracle.com/otndocs/jcp/jdbc-4_2-mrel2-spec/[JDBC Specification - Version 4.2]

View File

@ -37,6 +37,7 @@ include::appendices/Annotations.adoc[]
include::appendices/BestPractices.adoc[]
include::appendices/Legacy_Bootstrap.adoc[]
include::appendices/Legacy_DomainModel.adoc[]
include::appendices/LegacyBasicTypeResolution.adoc[]
include::appendices/Legacy_Criteria.adoc[]
include::appendices/Legacy_Native_Queries.adoc[]

View File

@ -595,7 +595,7 @@ See the <<chapters/domain/identifiers.adoc#identifiers-generators-table-configur
The {jpaJavadocUrlPrefix}Temporal.html[`@Temporal`] annotation is used to specify the `TemporalType` of the currently annotated `java.util.Date` or `java.util.Calendar` entity attribute.
See the <<chapters/domain/basic_types.adoc#basic-datetime,Basic temporal types>> chapter for more info.
See the <<chapters/domain/basic_types.adoc#basic-temporal,Basic temporal types>> chapter for more info.
[[annotations-jpa-transient]]
==== `@Transient`

View File

@ -0,0 +1,351 @@
:sourcedir: ../../../../test/java/org/hibernate/userguide/mapping
:extrasdir: extras
:originalextrasdir: ../chapters/domain/extras
[[basic-legacy]]
== Legacy BasicType resolution
Versions prior to 6.0 statically combined the `JavaTypeDescriptor`, `JdbcTypeDescriptor`, `BasicValueConverter` and
`MutabilityPlan` aspects within the `org.hibernate.type.BasicType` contract. Hibernate's legacy strategy for resolving
a basic type is based on finding the implementation of `org.hibernate.type.BasicType` to use.
This appendix will describe the legacy approach for influencing the mapping of basic types.
Generally speaking, this resolution uses an internal registry of `BasicType` implementations
registered under one-or-more "registration keys". The tables in <<basic-legacy-provided>> describe
the initial set of `BasicType` references registered by Hibernate. <<basic-legacy-registry>>
describes this `BasicTypeRegistry`.
Users can also override mappings in the `BasicTypeRegistry` or extend them to map new types, as described
in <<basic-custom-type>>.
[[basic-legacy-provided]]
=== Hibernate-provided BasicTypes
.Standard BasicTypes
[cols="<.^,<.^,<.^,<.^",options="header",]
|=======================================================================================================================================================================================================================================================================================
|Hibernate type (org.hibernate.type package) |JDBC type |Java type |BasicTypeRegistry key(s)
|StringType |VARCHAR |java.lang.String |string, java.lang.String
|MaterializedClob |CLOB |java.lang.String |materialized_clob
|TextType |LONGVARCHAR |java.lang.String |text
|CharacterType |CHAR |char, java.lang.Character |character, char, java.lang.Character
|BooleanType |BOOLEAN |boolean, java.lang.Boolean |boolean, java.lang.Boolean
|NumericBooleanType |INTEGER, 0 is false, 1 is true |boolean, java.lang.Boolean |numeric_boolean
|YesNoType |CHAR, 'N'/'n' is false, 'Y'/'y' is true. The uppercase value is written to the database. |boolean, java.lang.Boolean |yes_no
|TrueFalseType |CHAR, 'F'/'f' is false, 'T'/'t' is true. The uppercase value is written to the database. |boolean, java.lang.Boolean |true_false
|ByteType |TINYINT |byte, java.lang.Byte |byte, java.lang.Byte
|ShortType |SMALLINT |short, java.lang.Short |short, java.lang.Short
|IntegerType |INTEGER |int, java.lang.Integer |integer, int, java.lang.Integer
|LongType |BIGINT |long, java.lang.Long |long, java.lang.Long
|FloatType |FLOAT |float, java.lang.Float |float, java.lang.Float
|DoubleType |DOUBLE |double, java.lang.Double |double, java.lang.Double
|BigIntegerType |NUMERIC |java.math.BigInteger |big_integer, java.math.BigInteger
|BigDecimalType |NUMERIC |java.math.BigDecimal |big_decimal, java.math.bigDecimal
|TimestampType |TIMESTAMP |java.util.Date |timestamp, java.sql.Timestamp, java.util.Date
|DbTimestampType |TIMESTAMP |java.util.Date |dbtimestamp
|TimeType |TIME |java.util.Date |time, java.sql.Time
|DateType |DATE |java.util.Date |date, java.sql.Date
|CalendarType |TIMESTAMP |java.util.Calendar |calendar, java.util.Calendar, java.util.GregorianCalendar
|CalendarDateType |DATE |java.util.Calendar |calendar_date
|CalendarTimeType |TIME |java.util.Calendar |calendar_time
|CurrencyType |VARCHAR |java.util.Currency |currency, java.util.Currency
|LocaleType |VARCHAR |java.util.Locale |locale, java.util.Locale
|TimeZoneType |VARCHAR, using the TimeZone ID |java.util.TimeZone |timezone, java.util.TimeZone
|UrlType |VARCHAR |java.net.URL |url, java.net.URL
|ClassType |VARCHAR (class FQN) |java.lang.Class |class, java.lang.Class
|BlobType |BLOB |java.sql.Blob |blob, java.sql.Blob
|ClobType |CLOB |java.sql.Clob |clob, java.sql.Clob
|BinaryType |VARBINARY |byte[] |binary, byte[]
|MaterializedBlobType |BLOB |byte[] |materialized_blob
|ImageType |LONGVARBINARY |byte[] |image
|WrapperBinaryType |VARBINARY |java.lang.Byte[] |wrapper-binary, Byte[], java.lang.Byte[]
|CharArrayType |VARCHAR |char[] |characters, char[]
|CharacterArrayType |VARCHAR |java.lang.Character[] |wrapper-characters, Character[], java.lang.Character[]
|UUIDBinaryType |BINARY |java.util.UUID |uuid-binary, java.util.UUID
|UUIDCharType |CHAR, can also read VARCHAR |java.util.UUID |uuid-char
|PostgresUUIDType |PostgreSQL UUID, through Types#OTHER, which complies to the PostgreSQL JDBC driver definition |java.util.UUID |pg-uuid
|SerializableType |VARBINARY |implementors of java.lang.Serializable |Unlike the other value types, multiple instances of this type are registered. It is registered once under java.io.Serializable, and registered under the specific java.io.Serializable implementation class names.
|StringNVarcharType |NVARCHAR |java.lang.String |nstring
|NTextType |LONGNVARCHAR |java.lang.String |ntext
|NClobType |NCLOB |java.sql.NClob |nclob, java.sql.NClob
|MaterializedNClobType |NCLOB |java.lang.String |materialized_nclob
|PrimitiveCharacterArrayNClobType |NCHAR |char[] |N/A
|CharacterNCharType |NCHAR |java.lang.Character |ncharacter
|CharacterArrayNClobType |NCLOB |java.lang.Character[] |N/A
|RowVersionType |VARBINARY |byte[] |row_version
|ObjectType |VARCHAR |implementors of java.lang.Serializable | object, java.lang.Object
|=======================================================================================================================================================================================================================================================================================
.Java 8 BasicTypes
[cols="<.^,<.^,<.^,<.^",options="header",]
|=================================================================================================
|Hibernate type (org.hibernate.type package) |JDBC type |Java type |BasicTypeRegistry key(s)
|DurationType |BIGINT |java.time.Duration |Duration, java.time.Duration
|InstantType |TIMESTAMP |java.time.Instant |Instant, java.time.Instant
|LocalDateTimeType |TIMESTAMP |java.time.LocalDateTime |LocalDateTime, java.time.LocalDateTime
|LocalDateType |DATE |java.time.LocalDate |LocalDate, java.time.LocalDate
|LocalTimeType |TIME |java.time.LocalTime |LocalTime, java.time.LocalTime
|OffsetDateTimeType |TIMESTAMP |java.time.OffsetDateTime |OffsetDateTime, java.time.OffsetDateTime
|OffsetTimeType |TIME |java.time.OffsetTime |OffsetTime, java.time.OffsetTime
|ZonedDateTimeType |TIMESTAMP |java.time.ZonedDateTime |ZonedDateTime, java.time.ZonedDateTime
|=================================================================================================
.Hibernate Spatial BasicTypes
[cols="<.^,<.^,<.^,<.^",options="header",]
|=================================================================================================
|Hibernate type (org.hibernate.spatial package) |JDBC type |Java type |BasicTypeRegistry key(s)
|JTSGeometryType |depends on the dialect | com.vividsolutions.jts.geom.Geometry |jts_geometry, and the class names of Geometry and its subclasses
|GeolatteGeometryType |depends on the dialect | org.geolatte.geom.Geometry |geolatte_geometry, and the class names of Geometry and its subclasses
|=================================================================================================
[NOTE]
====
To use the Hibernate Spatial types, you must add the `hibernate-spatial` dependency to your classpath _and_ use an `org.hibernate.spatial.SpatialDialect` implementation.
See the <<chapters/query/spatial/Spatial.adoc#spatial,Spatial>> chapter for more details.
====
[[basic-legacy-registry]]
=== BasicTypeRegistry
We said before that a Hibernate type is not a Java type, nor an SQL type, but that it understands both and performs the marshalling between them.
But looking at the basic type mappings from the previous examples,
how did Hibernate know to use its `org.hibernate.type.StringType` for mapping for `java.lang.String` attributes,
or its `org.hibernate.type.IntegerType` for mapping `java.lang.Integer` attributes?
The answer lies in a service inside Hibernate called the `org.hibernate.type.BasicTypeRegistry`, which maintains a
map of `org.hibernate.type.BasicType` instances keyed by a name.
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 the implicit resolution.
[NOTE]
====
A thorough discussion of `BasicTypeRegistry` and all the different ways to contribute types is beyond the scope of this documentation.
Please see the http://docs.jboss.org/hibernate/orm/{majorMinorVersion}/integrationguide/html_single/Hibernate_Integration_Guide.html[Integration Guide] for complete details.
====
As an example, take a String attribute such as we saw before with Product#sku.
Since there is no explicit type mapping, Hibernate looks to the `BasicTypeRegistry` to find the registered
mapping for `java.lang.String`.
As a baseline within `BasicTypeRegistry`, Hibernate follows the recommended mappings of JDBC for Java types.
JDBC recommends mapping Strings to VARCHAR, which is the exact mapping that `StringType` handles.
So that is the baseline mapping within `BasicTypeRegistry` for Strings.
Applications can also extend (add new `BasicType` registrations) or override (replace an existing `BasicType` registration) using one of the
`MetadataBuilder#applyBasicType` methods or the `MetadataBuilder#applyTypes` method during bootstrap.
For more details, see <<basic-custom-type>> section.
[[basic-type-annotation]]
=== Explicit BasicTypes
Sometimes you want a particular attribute to be handled differently.
Occasionally Hibernate will implicitly pick a `BasicType` that you do not want (and for some reason you do not want to adjust the `BasicTypeRegistry`).
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, indent=0]
----
include::{sourcedir}/basic/ExplicitTypeTest.java[tags=basic-type-annotation-example]
----
====
This tells Hibernate to store the Strings as nationalized data.
This is just for illustration purposes; for better ways to indicate nationalized character data see <<basic-nationalized>> section.
Additionally, the description is to be handled as a LOB. Again, for better ways to indicate LOBs see <<basic-lob>> section.
The `org.hibernate.annotations.Type#type` attribute can name any of the following:
* Fully qualified name of any `org.hibernate.type.Type` implementation
* Any key registered with `BasicTypeRegistry`
* The name of any known _type definitions_
[[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.util.BigInteger` to `VARCHAR` columns, or support completely new types.
There are two approaches to developing a custom type:
- implementing a `BasicType` and registering it
- implementing a `UserType` which doesn't require type registration
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, if the value is stored in a single database column, it's much more convenient to extend the `AbstractStandardBasicType` or the `AbstractSingleColumnStandardBasicType` Hibernate classes.
====
First, we need to extend the `AbstractSingleColumnStandardBasicType` like this:
[[basic-custom-type-BitSetType-example]]
.Custom `BasicType` implementation
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/BitSetType.java[tags=basic-custom-type-BitSetType-example]
----
====
The `AbstractSingleColumnStandardBasicType` requires an `jdbcTypeDescriptor` and a `javaTypeDescriptor`.
The `jdbcTypeDescriptor` is `VarcharTypeDescriptor.INSTANCE` because the database column is a VARCHAR.
On the Java side, we need to use a `BitSetJavaType` instance which can be implemented like this:
[[basic-custom-type-BitSetTypeDescriptor-example]]
.Custom `AbstractTypeDescriptor` implementation
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/BitSetTypeDescriptor.java[tags=basic-custom-type-BitSetTypeDescriptor-example]
----
====
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]
----
====
Alternatively, you can use the `@TypeDef` and skip the registration phase:
[[basic-custom-type-BitSetTypeDef-mapping-example]]
.Using `@TypeDef` to register a custom Type
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/BitSetTypeDefTest.java[tags=basic-custom-type-BitSetTypeDef-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::{originalextrasdir}/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 registering a name, the `UserType` mapping requires the fully qualified class 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::{originalextrasdir}/basic/basic-custom-type-BitSetUserType-persistence-sql-example.sql[]
----
====

View File

@ -1,7 +1,7 @@
[[batch]]
== Batching
:sourcedir: ../../../../../test/java/org/hibernate/userguide/batch
:bulkid-sourcedir: ../../../../../../../hibernate-core/src/test/java/org/hibernate/test/bulkid
:bulkid-sourcedir: ../../../../../../../hibernate-core/src/test_legacy/java/org/hibernate/test/bulkid
:extrasdir: extras
[[batch-jdbcbatch]]

View File

@ -29,4 +29,3 @@ include::natural_id.adoc[]
include::dynamic_model.adoc[]
include::inheritance.adoc[]
include::immutability.adoc[]
include::jdbc_mappings.adoc[]

View File

@ -1,66 +0,0 @@
[[jdbc-mapping]]
=== JDBC Mappings
Historically Hibernate's BasicType / UserType system is based on a static binding between a Java type
(`JavaTypeDescriptor`) and a SQL/JDBC type (`JdbcTypeDescriptor`). 6.0 introduces the ability to influence
the `JavaTypeDescriptor` and `JdbcTypeDescriptor` independently. Under this new approach, the resolution of a
basic value mapping comes down to:
* `JavaTypeDescriptor` to use
* `JdbcTypeDescriptor` to use
* `BasicValueConverter` to use (if one)
* `MutabilityPlan` to use
Each of these pieces can be influenced independently.
==== JavaTypeDescriptor
`@JavaType` can be used to explicitly specify the `JavaTypeDescriptor` to use for a particular mapping.
`@JavaTypeRegistration` can be used to replace the default `Class` -> `JavaTypeDescriptor` mapping as part
of the `JavaTypeDescriptorRegistry`.
`@Temporal` hints at the `JavaTypeDescriptor` to use in certain cases. E.g. `java.util.Date` can represent a
`java.sql.Date`, `java.sql.Time` or `java.sql.Timestamp` - the `TemporalType` specified by the `@Temporal`
indicates which specific `JavaTypeDescriptor` to use...
An `AttributeConverter` can also influence the `JavaTypeDescriptor` used in certain cases.
==== SqlTypeDescriptor
`@JdbcType` can be used to explicitly specify the `JdbcTypeDescriptor` to use for a particular mapping.
`@JdbcTypeCode` can be used to indicate the `JdbcTypeDescriptorRegistry` entry to use. `@JdbcTypeRegistration` can
be used to register a `JdbcTypeDescriptor` with the `JdbcTypeDescriptorRegistry`.
`@MapKeyJdbcType` and `@MapKeyJdbcTypeCode` work the same as `@JdbcType` and `@JdbcTypeCode`, respectively, except
describing the `JdbcTypeDescriptor` to use for the map's key. In which case, `@JdbcType` and `@JdbcTypeCode` refer
to the map's values.
For character and binary data, the JPA `@Lob` annotation can be used to indicate that a JDBC BLOB, CLOB, NCLOB should
be used.
For character data, `@Nationalized` can be used to indicate that the JDBC nationalized variant should be used.
E.g. `Types.CLOB` -> `Types.CLOB`, `Types.VARCHAR` -> `Types.NVARCHAR`, etc
`@Enumerated` influences the `JdbcTypeDescriptor` to use by the `EnumType` specified. `EnumType#ORDINAL` implies
that `Types.TINYINT` should be used. `EnumType#STRING` implies that `Types.VARCHAR` should be used.
`@Temporal` can also influence the `JdbcTypeDescriptor` used.
An `AttributeConverter` can also influence the `JdbcTypeDescriptor` to use by the Java type it reports for its
"relational type"
==== BasicValueConverter
At the moment, the only ways to apply a `BasicValueConverter` are by using `@Enumerated` and by applying a JPA
`AttributeConverter`.
==== MutabilityPlan
`MutabilityPlan` can be influenced by either `@Immutable` or `@Mutability`.
By default, `JavaTypeDescriptor#getMutabilityPlan` is used

View File

@ -1,8 +1,8 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* 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.flush;
@ -55,7 +55,7 @@ public class AlwaysFlushTest extends BaseEntityManagerFunctionalTestCase {
Session session = entityManager.unwrap( Session.class);
assertTrue(((Number) session
.createNativeQuery("select count(*) from Person")
.setFlushMode( FlushMode.ALWAYS)
.setHibernateFlushMode( FlushMode.ALWAYS)
.uniqueResult()).intValue() == 1);
//end::flushing-always-flush-sql-example[]
});

View File

@ -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.math.BigDecimal;
import java.sql.Types;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
/**
* Tests for mapping `BigInteger` values
*
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = BigDecimalMappingTests.EntityOfBigDecimals.class )
@SessionFactory
public class BigDecimalMappingTests {
@Test
public void testMappings(SessionFactoryScope scope) {
// first, verify the type selections...
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityOfBigDecimals.class );
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "wrapper" );
assertThat( attribute.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( BigDecimal.class ) );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( BigDecimal.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), is( Types.NUMERIC ) );
}
// and try to use the mapping
scope.inTransaction(
(session) -> session.persist( new EntityOfBigDecimals( 1, BigDecimal.TEN ) )
);
scope.inTransaction(
(session) -> session.get( EntityOfBigDecimals.class, 1 )
);
}
@AfterEach
public void dropData(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> session.createQuery( "delete EntityOfBigDecimals" ).executeUpdate()
);
}
@Entity( name = "EntityOfBigDecimals" )
@Table( name = "EntityOfBigDecimals" )
public static class EntityOfBigDecimals {
@Id
Integer id;
//tag::basic-bigdecimal-example-implicit[]
// will be mapped using NUMERIC
BigDecimal wrapper;
//end::basic-bigdecimal-example-implicit[]
public EntityOfBigDecimals() {
}
public EntityOfBigDecimals(Integer id, BigDecimal wrapper) {
this.id = id;
this.wrapper = wrapper;
}
}
}

View File

@ -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.math.BigInteger;
import java.sql.Types;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
/**
* Tests for mapping `BigInteger` values
*
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = BigIntegerMappingTests.EntityOfBigIntegers.class )
@SessionFactory
public class BigIntegerMappingTests {
@Test
public void testMappings(SessionFactoryScope scope) {
// first, verify the type selections...
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityOfBigIntegers.class );
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "wrapper" );
assertThat( attribute.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( BigInteger.class ) );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( BigInteger.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), is( Types.NUMERIC ) );
}
// and try to use the mapping
scope.inTransaction(
(session) -> session.persist( new EntityOfBigIntegers( 1, BigInteger.TEN ) )
);
scope.inTransaction(
(session) -> session.get( EntityOfBigIntegers.class, 1 )
);
}
@AfterEach
public void dropData(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> session.createQuery( "delete EntityOfBigIntegers" ).executeUpdate()
);
}
@Entity( name = "EntityOfBigIntegers" )
@Table( name = "EntityOfBigIntegers" )
public static class EntityOfBigIntegers {
@Id
Integer id;
//tag::basic-biginteger-example-implicit[]
// will be mapped using NUMERIC
BigInteger wrapper;
//end::basic-biginteger-example-implicit[]
public EntityOfBigIntegers() {
}
public EntityOfBigIntegers(Integer id, BigInteger wrapper) {
this.id = id;
this.wrapper = wrapper;
}
}
}

View File

@ -0,0 +1,111 @@
/*
* 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.sql.Types;
import java.util.BitSet;
import javax.persistence.AttributeConverter;
import javax.persistence.Convert;
import javax.persistence.Converter;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.isOneOf;
/**
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = BitSetConverterTests.Product.class )
@SessionFactory
public class BitSetConverterTests {
@Test
public void verifyMappings(SessionFactoryScope scope) {
final SessionFactoryImplementor sessionFactory = scope.getSessionFactory();
final MappingMetamodel domainModel = sessionFactory.getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( Product.class );
final BasicAttributeMapping attributeMapping = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "bitSet" );
assertThat( attributeMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( BitSet.class ) );
assertThat( attributeMapping.getValueConverter(), instanceOf( JpaAttributeConverter.class ) );
final JpaAttributeConverter converter = (JpaAttributeConverter) attributeMapping.getValueConverter();
assertThat( converter.getConverterBean().getBeanClass(), equalTo( BitSetConverter.class ) );
assertThat(
attributeMapping.getJdbcMapping().getJdbcTypeDescriptor().getJdbcTypeCode(),
isOneOf( Types.VARCHAR, Types.NVARCHAR )
);
assertThat( attributeMapping.getJdbcMapping().getJavaTypeDescriptor().getJavaTypeClass(), equalTo( String.class ) );
}
@Table(name = "products")
//tag::basic-bitset-example-convert[]
@Entity(name = "Product")
public static class Product {
@Id
private Integer id;
@Convert( converter = BitSetConverter.class )
private BitSet bitSet;
//Getters and setters are omitted for brevity
//end::basic-bitset-example-convert[]
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;
}
//tag::basic-bitset-example-convert[]
}
//end::basic-bitset-example-convert[]
//tag::basic-bitset-example-converter[]
@Converter( autoApply = true )
public static class BitSetConverter implements AttributeConverter<BitSet,String> {
@Override
public String convertToDatabaseColumn(BitSet attribute) {
return BitSetHelper.bitSetToString( attribute );
}
@Override
public BitSet convertToEntityAttribute(String dbData) {
return BitSetHelper.stringToBitSet( dbData );
}
}
//end::basic-bitset-example-converter[]
}

View File

@ -0,0 +1,51 @@
/*
* 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;
/**
* @author Steve Ebersole
*/
public class BitSetHelper {
public static final String DELIMITER = ",";
public static final byte[] BYTES = new byte[] { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
public static String bitSetToString(BitSet bitSet) {
StringBuilder builder = new StringBuilder();
for ( long token : bitSet.toLongArray() ) {
if ( builder.length() > 0 ) {
builder.append( DELIMITER );
}
builder.append( Long.toString( token, 2 ) );
}
return builder.toString();
}
public static BitSet stringToBitSet(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 );
}
public static byte[] bitSetToBytes(BitSet bitSet) {
return bitSet == null ? null : bitSet.toByteArray();
}
public static BitSet bytesToBitSet(byte[] bytes) {
return bytes == null || bytes.length == 0
? null
: BitSet.valueOf( bytes );
}
}

View File

@ -0,0 +1,96 @@
/*
* 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.sql.Types;
import java.util.BitSet;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import org.hamcrest.Matchers;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.isOneOf;
import static org.hamcrest.Matchers.nullValue;
/**
* Tests for using BitSet without any mapping details
*
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = BitSetImplicitTests.Product.class )
@SessionFactory
public class BitSetImplicitTests {
@Test
public void verifyMappings(SessionFactoryScope scope) {
final SessionFactoryImplementor sessionFactory = scope.getSessionFactory();
final MappingMetamodel domainModel = sessionFactory.getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( Product.class );
final BasicAttributeMapping attributeMapping = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "bitSet" );
assertThat( attributeMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( BitSet.class ) );
assertThat( attributeMapping.getValueConverter(), nullValue() );
assertThat(
attributeMapping.getJdbcMapping().getJdbcTypeDescriptor().getJdbcTypeCode(),
is( Types.VARBINARY )
);
// it will just be serialized
assertThat( attributeMapping.getJdbcMapping().getJavaTypeDescriptor().getJavaTypeClass(), equalTo( BitSet.class ) );
}
@Table(name = "products")
//tag::basic-bitset-example-implicit[]
@Entity(name = "Product")
public static class Product {
@Id
private Integer id;
private BitSet bitSet;
//Getters and setters are omitted for brevity
//end::basic-bitset-example-implicit[]
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;
}
//tag::basic-bitset-example-implicit[]
}
//end::basic-bitset-example-implicit[]
}

View File

@ -0,0 +1,78 @@
package org.hibernate.userguide.mapping.basic;
import java.sql.Types;
import java.util.BitSet;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.AbstractClassTypeDescriptor;
import org.hibernate.type.descriptor.java.MutabilityPlan;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
/**
* @author Vlad Mihalcea
*/
//tag::basic-bitset-example-java-type[]
public class BitSetJavaType extends AbstractClassTypeDescriptor<BitSet> {
public static final BitSetJavaType INSTANCE = new BitSetJavaType();
public BitSetJavaType() {
super( BitSet.class );
}
@Override
public MutabilityPlan<BitSet> getMutabilityPlan() {
return BitSetMutabilityPlan.INSTANCE;
}
@Override
public JdbcTypeDescriptor getRecommendedJdbcType(JdbcTypeDescriptorIndicators indicators) {
return indicators.getTypeConfiguration()
.getJdbcTypeDescriptorRegistry()
.getDescriptor( Types.VARCHAR );
}
@Override
public String toString(BitSet value) {
return BitSetHelper.bitSetToString( value );
}
@Override
public BitSet fromString(String string) {
return BitSetHelper.stringToBitSet( string );
}
@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);
}
if ( type.isArray() ) {
if ( type.getComponentType() == byte.class ) {
return (X) value.toByteArray();
}
}
throw unknownUnwrap( type );
}
public <X> BitSet wrap(X value, WrapperOptions options) {
if ( value == null ) {
return null;
}
if ( value instanceof String ) {
return fromString( (String) value );
}
if ( value instanceof BitSet ) {
return (BitSet) value;
}
throw unknownWrap( value.getClass() );
}
}
//end::basic-bitset-example-java-type[]

View File

@ -0,0 +1,84 @@
/*
* 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.Basic;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.JavaTypeRegistration;
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf;
/**
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = BitSetJavaTypeRegistrationTests.Product.class )
@SessionFactory
public class BitSetJavaTypeRegistrationTests {
@Test
public void testResolution(SessionFactoryScope scope) {
final EntityPersister productType = scope.getSessionFactory()
.getRuntimeMetamodels()
.getMappingMetamodel()
.findEntityDescriptor( Product.class );
final SingularAttributeMapping bitSetAttribute = (SingularAttributeMapping) productType.findAttributeMapping( "bitSet" );
// make sure BitSetTypeDescriptor was selected
assertThat( bitSetAttribute.getJavaTypeDescriptor(), instanceOf( BitSetJavaType.class ) );
}
@Table(name = "Product")
//tag::basic-bitset-example-java-type-global[]
@Entity(name = "Product")
@JavaTypeRegistration( javaType = BitSet.class, descriptorClass = BitSetJavaType.class )
public static class Product {
@Id
private Integer id;
private BitSet bitSet;
//Constructors, getters, and setters are omitted for brevity
//end::basic-bitset-example-java-type-global[]
public Product() {
}
public Product(Number id, BitSet bitSet) {
this.id = id.intValue();
this.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;
}
//tag::basic-bitset-example-java-type-global[]
}
//end::basic-bitset-example-java-type-global[]
}

View File

@ -0,0 +1,86 @@
/*
* 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.Basic;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.JavaType;
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf;
/**
* Tests for using an explicit {@link JavaType}
*
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = BitSetJavaTypeTests.Product.class )
@SessionFactory
public class BitSetJavaTypeTests {
@Test
public void testResolution(SessionFactoryScope scope) {
final EntityPersister productType = scope.getSessionFactory()
.getRuntimeMetamodels()
.getMappingMetamodel()
.findEntityDescriptor( Product.class );
final SingularAttributeMapping bitSetAttribute = (SingularAttributeMapping) productType.findAttributeMapping( "bitSet" );
// make sure BitSetTypeDescriptor was selected
assertThat( bitSetAttribute.getJavaTypeDescriptor(), instanceOf( BitSetJavaType.class ) );
}
@Table(name = "Product")
//tag::basic-bitset-example-java-type-local[]
@Entity(name = "Product")
public static class Product {
@Id
private Integer id;
@JavaType( BitSetJavaType.class )
private BitSet bitSet;
//Constructors, getters, and setters are omitted for brevity
//end::basic-bitset-example-java-type-local[]
public Product() {
}
public Product(Number id, BitSet bitSet) {
this.id = id.intValue();
this.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;
}
//tag::basic-bitset-example-java-type-local[]
}
//end::basic-bitset-example-java-type-local[]
}

View File

@ -0,0 +1,120 @@
/*
* 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.sql.Types;
import java.util.BitSet;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
/**
* Tests for {@link org.hibernate.annotations.JdbcTypeCode}
*
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = BitSetJdbcTypeCodeTests.Product.class )
@SessionFactory
public class BitSetJdbcTypeCodeTests {
@Test
public void verifyMappings(SessionFactoryScope scope) {
final SessionFactoryImplementor sessionFactory = scope.getSessionFactory();
final MappingMetamodel domainModel = sessionFactory.getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( Product.class );
final BasicAttributeMapping attributeMapping = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "bitSet" );
assertThat( attributeMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( BitSet.class ) );
assertThat( attributeMapping.getValueConverter(), nullValue() );
assertThat(
attributeMapping.getJdbcMapping().getJdbcTypeDescriptor().getJdbcTypeCode(),
is( Types.VARBINARY )
);
assertThat( attributeMapping.getJdbcMapping().getJavaTypeDescriptor().getJavaTypeClass(), equalTo( BitSet.class ) );
scope.inTransaction(
(session) -> {
session.persist( new Product( 1, BitSet.valueOf( BitSetHelper.BYTES ) ) );
}
);
scope.inSession(
(session) -> {
final Product product = session.get( Product.class, 1 );
assertThat( product.getBitSet(), equalTo( BitSet.valueOf( BitSetHelper.BYTES ) ) );
}
);
}
@AfterEach
public void dropData(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> session.createQuery( "delete Product" ).executeUpdate()
);
}
@Table(name = "Product")
//tag::basic-bitset-example-jdbc-type-code[]
@Entity(name = "Product")
public static class Product {
@Id
private Integer id;
@JdbcTypeCode( Types.VARBINARY )
private BitSet bitSet;
//Constructors, getters, and setters are omitted for brevity
//end::basic-bitset-example-jdbc-type-code[]
public Product() {
}
public Product(Number id, BitSet bitSet) {
this.id = id.intValue();
this.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;
}
//tag::basic-bitset-example-jdbc-type-code[]
}
//end::basic-bitset-example-jdbc-type-code[]
}

View File

@ -0,0 +1,119 @@
/*
* 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.sql.Types;
import java.util.BitSet;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.annotations.JdbcTypeRegistration;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
/**
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = BitSetJdbcTypeRegistrationTests.Product.class )
@SessionFactory
public class BitSetJdbcTypeRegistrationTests {
@Test
public void verifyMappings(SessionFactoryScope scope) {
final SessionFactoryImplementor sessionFactory = scope.getSessionFactory();
final MappingMetamodel domainModel = sessionFactory.getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( Product.class );
final BasicAttributeMapping attributeMapping = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "bitSet" );
assertThat( attributeMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( BitSet.class ) );
assertThat( attributeMapping.getValueConverter(), nullValue() );
assertThat(
attributeMapping.getJdbcMapping().getJdbcTypeDescriptor().getJdbcTypeCode(),
is( Types.VARBINARY )
);
assertThat( attributeMapping.getJdbcMapping().getJavaTypeDescriptor().getJavaTypeClass(), equalTo( BitSet.class ) );
scope.inTransaction(
(session) -> {
session.persist( new Product( 1, BitSet.valueOf( BitSetHelper.BYTES ) ) );
}
);
scope.inSession(
(session) -> {
final Product product = session.get( Product.class, 1 );
assertThat( product.getBitSet(), equalTo( BitSet.valueOf( BitSetHelper.BYTES ) ) );
}
);
}
@AfterEach
public void dropData(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> session.createQuery( "delete Product" ).executeUpdate()
);
}
@Table(name = "Product")
//tag::basic-bitset-example-jdbc-type-global[]
@Entity(name = "Product")
@JdbcTypeRegistration( CustomBinaryJdbcType.class )
public static class Product {
@Id
private Integer id;
private BitSet bitSet;
//Constructors, getters, and setters are omitted for brevity
//end::basic-bitset-example-jdbc-type-global[]
public Product() {
}
public Product(Number id, BitSet bitSet) {
this.id = id.intValue();
this.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;
}
//tag::basic-bitset-example-jdbc-type-global[]
}
//end::basic-bitset-example-jdbc-type-global[]
}

View File

@ -0,0 +1,119 @@
/*
* 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.sql.Types;
import java.util.BitSet;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.JdbcType;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
/**
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = BitSetJdbcTypeTests.Product.class )
@SessionFactory
public class BitSetJdbcTypeTests {
@Test
public void verifyMappings(SessionFactoryScope scope) {
final SessionFactoryImplementor sessionFactory = scope.getSessionFactory();
final MappingMetamodel domainModel = sessionFactory.getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( Product.class );
final BasicAttributeMapping attributeMapping = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "bitSet" );
assertThat( attributeMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( BitSet.class ) );
assertThat( attributeMapping.getValueConverter(), nullValue() );
assertThat(
attributeMapping.getJdbcMapping().getJdbcTypeDescriptor().getJdbcTypeCode(),
is( Types.VARBINARY )
);
assertThat( attributeMapping.getJdbcMapping().getJavaTypeDescriptor().getJavaTypeClass(), equalTo( BitSet.class ) );
scope.inTransaction(
(session) -> {
session.persist( new Product( 1, BitSet.valueOf( BitSetHelper.BYTES ) ) );
}
);
scope.inSession(
(session) -> {
final Product product = session.get( Product.class, 1 );
assertThat( product.getBitSet(), equalTo( BitSet.valueOf( BitSetHelper.BYTES ) ) );
}
);
}
@AfterEach
public void dropData(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> session.createQuery( "delete Product" ).executeUpdate()
);
}
@Table(name = "Product")
//tag::basic-bitset-example-jdbc-type-local[]
@Entity(name = "Product")
public static class Product {
@Id
private Integer id;
@JdbcType( CustomBinaryJdbcType.class )
private BitSet bitSet;
//Constructors, getters, and setters are omitted for brevity
//end::basic-bitset-example-jdbc-type-local[]
public Product() {
}
public Product(Number id, BitSet bitSet) {
this.id = id.intValue();
this.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;
}
//tag::basic-bitset-example-jdbc-type-local[]
}
//end::basic-bitset-example-jdbc-type-local[]
}

View File

@ -0,0 +1,43 @@
/*
* 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.io.Serializable;
import java.util.BitSet;
import org.hibernate.SharedSessionContract;
import org.hibernate.type.descriptor.java.MutabilityPlan;
/**
* @author Steve Ebersole
*/
public class BitSetMutabilityPlan implements MutabilityPlan<BitSet> {
/**
* Singleton access
*/
public static final BitSetMutabilityPlan INSTANCE = new BitSetMutabilityPlan();
@Override
public boolean isMutable() {
return true;
}
@Override
public BitSet deepCopy(BitSet value) {
return BitSet.valueOf( value.toByteArray() );
}
@Override
public Serializable disassemble(BitSet value, SharedSessionContract session) {
return value.toByteArray();
}
@Override
public BitSet assemble(Serializable cached, SharedSessionContract session) {
return BitSet.valueOf( (byte[]) cached );
}
}

View File

@ -18,7 +18,7 @@ public class BitSetType
public static final BitSetType INSTANCE = new BitSetType();
public BitSetType() {
super( VarcharTypeDescriptor.INSTANCE, BitSetTypeDescriptor.INSTANCE );
super( VarcharTypeDescriptor.INSTANCE, BitSetJavaType.INSTANCE );
}
@Override

View File

@ -10,48 +10,54 @@ import java.util.BitSet;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.hibernate.cfg.Configuration;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
import static org.junit.Assert.assertEquals;
/**
* @author Vlad Mihalcea
*/
public class BitSetTypeDefTest extends BaseCoreFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Product.class
};
}
@DomainModel( annotatedClasses = BitSetTypeDefTest.Product.class )
@SessionFactory
public class BitSetTypeDefTest {
@Test
public void test() {
public void test(SessionFactoryScope scope) {
//tag::basic-custom-type-BitSetTypeDef-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 );
} );
scope.inTransaction(
(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());
} );
scope.inTransaction(
(session) -> {
final Product product = session.get( Product.class, 1 );
assertEquals(bitSet, product.getBitSet());
}
);
//end::basic-custom-type-BitSetTypeDef-persistence-example[]
}
@AfterEach
public void dropData(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> session.createQuery( "delete Product" ).executeUpdate()
);
}
//tag::basic-custom-type-BitSetTypeDef-mapping-example[]
@Entity(name = "Product")
@TypeDef(

View File

@ -1,75 +0,0 @@
package org.hibernate.userguide.mapping.basic;
import java.util.BitSet;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.AbstractClassTypeDescriptor;
/**
* @author Vlad Mihalcea
*/
//tag::basic-custom-type-BitSetTypeDescriptor-example[]
public class BitSetTypeDescriptor extends AbstractClassTypeDescriptor<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[]

View File

@ -48,14 +48,14 @@ public class BitSetUserType implements UserType {
}
@Override
public Object nullSafeGet(
ResultSet rs, String[] names, SharedSessionContractImplementor 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 );
public Object nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, Object owner) throws SQLException {
String columnValue = (String) rs.getObject( position );
if ( rs.wasNull() ) {
columnValue = null;
}
log.debugv("Result set column {0} value is {1}", position, columnValue);
return BitSetHelper.stringToBitSet( columnValue );
}
@Override
@ -67,7 +67,7 @@ public class BitSetUserType implements UserType {
st.setNull( index, Types.VARCHAR );
}
else {
String stringValue = BitSetTypeDescriptor.INSTANCE.toString( (BitSet) value );
String stringValue = BitSetHelper.bitSetToString( (BitSet) value );
log.debugv("Binding {0} to parameter {1} ", stringValue, index);
st.setString( index, stringValue );
}

View File

@ -0,0 +1,189 @@
/*
* 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.sql.Types;
import javax.persistence.Basic;
import javax.persistence.Convert;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.isOneOf;
/**
* Tests for mapping boolean values
*
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = BooleanMappingTests.EntityOfBooleans.class )
@SessionFactory
public class BooleanMappingTests {
@Test
public void verifyMappings(SessionFactoryScope scope) {
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityOfBooleans.class );
{
final BasicAttributeMapping implicit = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "implicit" );
final JdbcMapping jdbcMapping = implicit.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaType(), equalTo( Boolean.class ) );
assertThat(
jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(),
// the implicit mapping will depend on the Dialect
isOneOf( Types.BOOLEAN, Types.BIT, Types.TINYINT )
);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Converters
{
final BasicAttributeMapping convertedYesNo = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "convertedYesNo" );
final JdbcMapping jdbcMapping = convertedYesNo.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaType(), equalTo( Character.class ) );
assertThat(
jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(),
// could be NCHAR if nationalization is globally enabled
isOneOf( Types.CHAR, Types.NCHAR )
);
}
{
final BasicAttributeMapping convertedTrueFalse = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "convertedTrueFalse" );
final JdbcMapping jdbcMapping = convertedTrueFalse.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaType(), equalTo( Character.class ) );
assertThat(
jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(),
// could be NCHAR if nationalization is globally enabled
isOneOf( Types.CHAR, Types.NCHAR )
);
}
{
final BasicAttributeMapping convertedNumeric = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "convertedNumeric" );
final JdbcMapping jdbcMapping = convertedNumeric.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaType(), equalTo( Integer.class ) );
assertThat(
jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(),
equalTo( Types.INTEGER )
);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Legacy
{
final BasicAttributeMapping legacyYesNo = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "legacyYesNo" );
final JdbcMapping jdbcMapping = legacyYesNo.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaType(), equalTo( Character.class ) );
assertThat(
jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(),
// could be NCHAR if nationalization is globally enabled
isOneOf( Types.CHAR, Types.NCHAR )
);
}
{
final BasicAttributeMapping legacyTrueFalse = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "legacyTrueFalse" );
final JdbcMapping jdbcMapping = legacyTrueFalse.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaType(), equalTo( Character.class ) );
assertThat(
jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(),
// could be NCHAR if nationalization is globally enabled
isOneOf( Types.CHAR, Types.NCHAR )
);
}
{
final BasicAttributeMapping legacyNumeric = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "legacyNumeric" );
final JdbcMapping jdbcMapping = legacyNumeric.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaType(), equalTo( Integer.class ) );
assertThat(
jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(),
equalTo( Types.INTEGER )
);
}
}
@Entity( name = "EntityOfBooleans" )
@Table( name = "EntityOfBooleans" )
public static class EntityOfBooleans {
@Id
Integer id;
//tag::basic-boolean-example-implicit[]
// this will be mapped to BIT or BOOLEAN on the database
@Basic
boolean implicit;
//end::basic-boolean-example-implicit[]
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// converted
//tag::basic-boolean-example-explicit-yes-no[]
// this will get mapped to CHAR or NCHAR with a conversion
@Basic
@Convert( converter = org.hibernate.type.YesNoConverter.class )
boolean convertedYesNo;
//end::basic-boolean-example-explicit-yes-no[]
//tag::basic-boolean-example-explicit-t-f[]
// this will get mapped to CHAR or NCHAR with a conversion
@Basic
@Convert( converter = org.hibernate.type.TrueFalseConverter.class )
boolean convertedTrueFalse;
//end::basic-boolean-example-explicit-t-f[]
//tag::basic-boolean-example-explicit-numeric[]
// this will get mapped to TINYINT with a conversion
@Basic
@Convert( converter = org.hibernate.type.NumericBooleanConverter.class )
boolean convertedNumeric;
//end::basic-boolean-example-explicit-numeric[]
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Legacy
//tag::basic-boolean-example-explicit-legacy-yes-no[]
// this will get mapped to CHAR or NCHAR with a conversion
@Basic
@org.hibernate.annotations.Type( type = "yes_no" )
boolean legacyYesNo;
//end::basic-boolean-example-explicit-legacy-yes-no[]
//tag::basic-boolean-example-explicit-legacy-t-f[]
// this will get mapped to CHAR or NCHAR with a conversion
@Basic
@org.hibernate.annotations.Type( type = "true_false" )
boolean legacyTrueFalse;
//end::basic-boolean-example-explicit-legacy-t-f[]
//tag::basic-boolean-example-explicit-legacy-numeric[]
// this will get mapped to TINYINT with a conversion
@Basic
@org.hibernate.annotations.Type( type = "numeric_boolean" )
boolean legacyNumeric;
//end::basic-boolean-example-explicit-legacy-numeric[]
}
}

View File

@ -0,0 +1,127 @@
/*
* 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.sql.Types;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
/**
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = ByteArrayMappingTests.EntityOfByteArrays.class )
@SessionFactory
public class ByteArrayMappingTests {
@Test
public void verifyMappings(SessionFactoryScope scope) {
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityOfByteArrays.class );
{
final BasicAttributeMapping primitive = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "primitive" );
final JdbcMapping jdbcMapping = primitive.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( byte[].class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.VARBINARY ) );
}
{
final BasicAttributeMapping primitive = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "wrapper" );
final JdbcMapping jdbcMapping = primitive.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Byte[].class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.VARBINARY ) );
}
{
final BasicAttributeMapping primitive = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "primitiveLob" );
final JdbcMapping jdbcMapping = primitive.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( byte[].class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.BLOB ) );
}
{
final BasicAttributeMapping primitive = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "wrapperLob" );
final JdbcMapping jdbcMapping = primitive.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Byte[].class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.BLOB ) );
}
scope.inTransaction(
(session) -> {
session.persist(
new EntityOfByteArrays( 1, "abc".getBytes(), new Byte[] { (byte) 1 } )
);
}
);
scope.inTransaction(
(session) -> session.get( EntityOfByteArrays.class, 1 )
);
}
@AfterEach
public void dropTestData(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> session.createQuery( "delete EntityOfByteArrays" ).executeUpdate()
);
}
@Entity( name = "EntityOfByteArrays" )
@Table( name = "EntityOfByteArrays" )
public static class EntityOfByteArrays {
@Id
public Integer id;
//tag::basic-bytearray-example[]
// mapped as VARBINARY
private byte[] primitive;
private Byte[] wrapper;
// mapped as (materialized) BLOB
@Lob
private byte[] primitiveLob;
@Lob
private Byte[] wrapperLob;
//end::basic-bytearray-example[]
public EntityOfByteArrays() {
}
public EntityOfByteArrays(Integer id, byte[] primitive, Byte[] wrapper) {
this.id = id;
this.primitive = primitive;
this.wrapper = wrapper;
this.primitiveLob = primitive;
this.wrapperLob = wrapper;
}
public EntityOfByteArrays(Integer id, byte[] primitive, Byte[] wrapper, byte[] primitiveLob, Byte[] wrapperLob) {
this.id = id;
this.primitive = primitive;
this.wrapper = wrapper;
this.primitiveLob = primitiveLob;
this.wrapperLob = wrapperLob;
}
}
}

View File

@ -0,0 +1,104 @@
/*
* 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.sql.Types;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.hamcrest.Matchers;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
/**
* Tests for mapping byte values
*
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = ByteMappingTests.EntityOfBytes.class )
@SessionFactory
public class ByteMappingTests {
@Test
public void testMappings(SessionFactoryScope scope) {
// first, verify the type selections...
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityOfBytes.class );
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "wrapper" );
assertThat( attribute.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Byte.class ) );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Byte.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), is( Types.TINYINT ) );
}
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "primitive" );
assertThat( attribute.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Byte.class ) );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Byte.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), is( Types.TINYINT ) );
}
// and try to use the mapping
scope.inTransaction(
(session) -> session.persist( new EntityOfBytes( 1, (byte) 3, (byte) 5 ) )
);
scope.inTransaction(
(session) -> session.get( EntityOfBytes.class, 1 )
);
}
@AfterEach
public void dropData(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> session.createQuery( "delete EntityOfBytes" ).executeUpdate()
);
}
@Entity( name = "EntityOfBytes" )
@Table( name = "EntityOfBytes" )
public static class EntityOfBytes {
@Id
Integer id;
//tag::basic-byte-example-implicit[]
// these will both be mapped using TINYINT
Byte wrapper;
byte primitive;
//end::basic-byte-example-implicit[]
public EntityOfBytes() {
}
public EntityOfBytes(Integer id, Byte wrapper, byte primitive) {
this.id = id;
this.wrapper = wrapper;
this.primitive = primitive;
}
}
}

View File

@ -0,0 +1,84 @@
/*
* 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.sql.Types;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;
import org.hibernate.annotations.Nationalized;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
/**
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = CharacterArrayMappingTests.EntityWithCharArrays.class )
@SessionFactory
public class CharacterArrayMappingTests {
@Test
public void verifyMappings(SessionFactoryScope scope) {
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityWithCharArrays.class );
{
final BasicAttributeMapping attributeMapping = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "primitive" );
final JdbcMapping jdbcMapping = attributeMapping.getJdbcMapping();
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.VARCHAR ) );
}
{
final BasicAttributeMapping attributeMapping = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "wrapper" );
final JdbcMapping jdbcMapping = attributeMapping.getJdbcMapping();
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.VARCHAR ) );
}
{
final BasicAttributeMapping attributeMapping = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "primitiveClob" );
final JdbcMapping jdbcMapping = attributeMapping.getJdbcMapping();
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.CLOB ) );
}
{
final BasicAttributeMapping attributeMapping = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "wrapperClob" );
final JdbcMapping jdbcMapping = attributeMapping.getJdbcMapping();
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.CLOB ) );
}
}
@Entity( name = "EntityWithCharArrays" )
@Table( name = "EntityWithCharArrays" )
public static class EntityWithCharArrays {
@Id
public Integer id;
//tag::basic-chararray-example[]
// mapped as VARCHAR
char[] primitive;
Character[] wrapper;
// mapped as CLOB
@Lob
char[] primitiveClob;
@Lob
Character[] wrapperClob;
//end::basic-chararray-example[]
}
}

View File

@ -0,0 +1,98 @@
/*
* 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.sql.Types;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;
import org.hibernate.annotations.Nationalized;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.NationalizationSupport;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
/**
* @see CharacterArrayMappingTests
*
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = CharacterArrayNationalizedMappingTests.EntityWithCharArrays.class )
@SessionFactory
@RequiresDialectFeature( feature = DialectFeatureChecks.SupportsNationalizedData.class )
public class CharacterArrayNationalizedMappingTests {
@Test
public void verifyMappings(SessionFactoryScope scope) {
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityWithCharArrays.class );
final Dialect dialect = scope.getSessionFactory().getJdbcServices().getDialect();
final NationalizationSupport nationalizationSupport = dialect.getNationalizationSupport();
{
final BasicAttributeMapping attributeMapping = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "primitiveNVarchar" );
final JdbcMapping jdbcMapping = attributeMapping.getJdbcMapping();
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( nationalizationSupport.getVarcharVariantCode() ) );
}
{
final BasicAttributeMapping attributeMapping = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "wrapperNVarchar" );
final JdbcMapping jdbcMapping = attributeMapping.getJdbcMapping();
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( nationalizationSupport.getVarcharVariantCode() ) );
}
{
final BasicAttributeMapping attributeMapping = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "primitiveNClob" );
final JdbcMapping jdbcMapping = attributeMapping.getJdbcMapping();
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( nationalizationSupport.getClobVariantCode() ) );
}
{
final BasicAttributeMapping attributeMapping = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "wrapperNClob" );
final JdbcMapping jdbcMapping = attributeMapping.getJdbcMapping();
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( nationalizationSupport.getClobVariantCode() ) );
}
}
@Entity( name = "EntityWithCharArrays" )
@Table( name = "EntityWithCharArrays" )
public static class EntityWithCharArrays {
@Id
public Integer id;
//tag::basic-nchararray-example[]
// mapped as NVARCHAR
@Nationalized
char[] primitiveNVarchar;
@Nationalized
Character[] wrapperNVarchar;
// mapped as NCLOB
@Lob
@Nationalized
char[] primitiveNClob;
@Lob
@Nationalized
Character[] wrapperNClob;
//end::basic-nchararray-example[]
}
}

View File

@ -0,0 +1,102 @@
/*
* 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.sql.Types;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.hamcrest.Matchers;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.isOneOf;
/**
* Tests for mapping `double` values
*
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = CharacterMappingTests.EntityOfCharacters.class )
@SessionFactory
public class CharacterMappingTests {
@Test
public void testMappings(SessionFactoryScope scope) {
// first, verify the type selections...
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityOfCharacters.class );
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "wrapper" );
assertThat( attribute.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Character.class ) );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Character.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.CHAR ) );
}
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "primitive" );
assertThat( attribute.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Character.class ) );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Character.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.CHAR ) );
}
// and try to use the mapping
scope.inTransaction(
(session) -> session.persist( new EntityOfCharacters( 1, 'A', 'b' ) )
);
scope.inTransaction(
(session) -> session.get( EntityOfCharacters.class, 1 )
);
}
@AfterEach
public void dropData(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> session.createQuery( "delete EntityOfCharacters" ).executeUpdate()
);
}
@Entity( name = "EntityOfCharacters" )
@Table( name = "EntityOfCharacters" )
public static class EntityOfCharacters {
@Id
Integer id;
//tag::basic-character-example-implicit[]
// these will be mapped using CHAR
Character wrapper;
char primitive;
//end::basic-character-example-implicit[]
public EntityOfCharacters() {
}
public EntityOfCharacters(Integer id, Character wrapper, char primitive) {
this.id = id;
this.wrapper = wrapper;
this.primitive = primitive;
}
}
}

View File

@ -0,0 +1,75 @@
/*
* 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.sql.Types;
import java.time.ZoneOffset;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
/**
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = ClassMappingTests.EntityWithClass.class )
@SessionFactory
public class ClassMappingTests {
@Test
public void verifyMappings(SessionFactoryScope scope) {
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityWithClass.class );
final BasicAttributeMapping duration = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "clazz" );
final JdbcMapping jdbcMapping = duration.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Class.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.VARCHAR ) );
scope.inTransaction(
(session) -> {
session.persist( new EntityWithClass( 1, String.class ) );
}
);
scope.inTransaction(
(session) -> session.find( EntityWithClass.class, 1 )
);
}
@Entity( name = "EntityWithClass" )
@Table( name = "EntityWithClass" )
public static class EntityWithClass {
@Id
private Integer id;
//tag::basic-Class-example[]
// mapped as VARCHAR
private Class<?> clazz;
//end::basic-Class-example[]
public EntityWithClass() {
}
public EntityWithClass(Integer id, Class<?> clazz) {
this.id = id;
this.clazz = clazz;
}
}
}

View File

@ -10,40 +10,47 @@ import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Lob;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
import org.hibernate.testing.orm.junit.Jpa;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertArrayEquals;
/**
* @author Vlad Mihalcea
*/
public class ClobCharArrayTest extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Product.class
};
}
@Jpa( annotatedClasses = ClobCharArrayTest.Product.class )
public class ClobCharArrayTest {
@Test
public void test() {
Integer productId = doInJPA( this::entityManagerFactory, entityManager -> {
final Product product = new Product( );
product.setId( 1 );
product.setName( "Mobile phone" );
product.setWarranty( "My product warranty".toCharArray() );
public void test(EntityManagerFactoryScope scope) {
Integer productId = scope.fromTransaction(
(em) -> {
final Product product = new Product( );
product.setId( 1 );
product.setName( "Mobile phone" );
product.setWarranty( "My product warranty".toCharArray() );
entityManager.persist( product );
return product.getId();
} );
doInJPA( this::entityManagerFactory, entityManager -> {
Product product = entityManager.find( Product.class, productId );
assertArrayEquals( "My product warranty".toCharArray(), product.getWarranty() );
} );
em.persist( product );
return product.getId();
}
);
scope.inTransaction(
(em) -> {
final Product product = em.find( Product.class, productId );
assertArrayEquals( "My product warranty".toCharArray(), product.getWarranty() );
}
);
}
@AfterEach
public void dropData(EntityManagerFactoryScope scope) {
scope.inTransaction(
(session) -> session.createQuery( "delete Product" ).executeUpdate()
);
}
//tag::basic-clob-char-array-example[]

View File

@ -9,7 +9,6 @@ package org.hibernate.userguide.mapping.basic;
import java.math.BigDecimal;
import java.util.Currency;
import java.util.Locale;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.Id;
@ -18,6 +17,7 @@ import org.hibernate.dialect.H2Dialect;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.orm.junit.NotImplementedYet;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
@ -26,6 +26,10 @@ import static org.junit.Assert.assertEquals;
/**
* @author Vlad Mihalcea
*/
@NotImplementedYet(
reason = "composition-as-basic (basic mapped to multiple columns) is no longer supported. See https://github.com/hibernate/hibernate-orm/discussions/3960",
strict = false
)
@RequiresDialect(H2Dialect.class)
public class ColumnTransformerTest extends BaseEntityManagerFunctionalTestCase {
@ -43,13 +47,15 @@ public class ColumnTransformerTest extends BaseEntityManagerFunctionalTestCase {
//tag::basic-datetime-temporal-date-persist-example[]
Savings savings = new Savings( );
savings.setId( 1L );
savings.setWallet( new MonetaryAmount( BigDecimal.TEN, Currency.getInstance( Locale.US ) ) );
savings.setCurrency( Currency.getInstance( Locale.US ) );
savings.setAmount( BigDecimal.TEN );
entityManager.persist( savings );
} );
doInJPA( this::entityManagerFactory, entityManager -> {
Savings savings = entityManager.find( Savings.class, 1L );
assertEquals( 10, savings.getWallet().getAmount().intValue());
assertEquals( 10, savings.getAmount().intValue());
assertEquals( Currency.getInstance( Locale.US ), savings.getCurrency() );
} );
//end::mapping-column-read-and-write-composite-type-persistence-example[]
}
@ -61,14 +67,12 @@ public class ColumnTransformerTest extends BaseEntityManagerFunctionalTestCase {
@Id
private Long id;
@Embedded
@ColumnTransformer(
forColumn = "money",
read = "money / 100",
write = "? * 100"
read = "amount / 100",
write = "? * 100"
)
// todo (6.0): needs a composite user type mechanism e.g. by providing a custom ComponentTuplizer/Instantiator
private MonetaryAmount wallet;
private BigDecimal amount;
private Currency currency;
//Getters and setters omitted for brevity
@ -81,12 +85,20 @@ public class ColumnTransformerTest extends BaseEntityManagerFunctionalTestCase {
this.id = id;
}
public MonetaryAmount getWallet() {
return wallet;
public BigDecimal getAmount() {
return amount;
}
public void setWallet(MonetaryAmount wallet) {
this.wallet = wallet;
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
public Currency getCurrency() {
return currency;
}
public void setCurrency(Currency currency) {
this.currency = currency;
}

View File

@ -0,0 +1,75 @@
/*
* 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.sql.Types;
import java.util.Currency;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
/**
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = CurrencyMappingTests.EntityWithCurrency.class )
@SessionFactory
public class CurrencyMappingTests {
@Test
public void verifyMappings(SessionFactoryScope scope) {
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityWithCurrency.class );
final BasicAttributeMapping duration = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "currency" );
final JdbcMapping jdbcMapping = duration.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Currency.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.VARCHAR ) );
scope.inTransaction(
(session) -> {
session.persist( new EntityWithCurrency( 1, Currency.getInstance( "USD" ) ) );
}
);
scope.inTransaction(
(session) -> session.find( EntityWithCurrency.class, 1 )
);
}
@Entity( name = "EntityWithCurrency" )
@Table( name = "EntityWithCurrency" )
public static class EntityWithCurrency {
@Id
private Integer id;
//tag::basic-Currency-example[]
// mapped as VARCHAR
private Currency currency;
//end::basic-Currency-example[]
public EntityWithCurrency() {
}
public EntityWithCurrency(Integer id, Currency currency) {
this.id = id;
this.currency = currency;
}
}
}

View File

@ -0,0 +1,42 @@
/*
* 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.sql.Types;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.VarbinaryTypeDescriptor;
/**
* JdbcTypeDescriptor for documentation
*
* @author Steve Ebersole
*/
public class CustomBinaryJdbcType implements JdbcTypeDescriptor {
@Override
public int getJdbcType() {
return Types.VARBINARY;
}
@Override
public boolean canBeRemapped() {
return false;
}
@Override
public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) {
return VarbinaryTypeDescriptor.INSTANCE.getBinder( javaTypeDescriptor );
}
@Override
public <X> ValueExtractor<X> getExtractor(JavaTypeDescriptor<X> javaTypeDescriptor) {
return VarbinaryTypeDescriptor.INSTANCE.getExtractor( javaTypeDescriptor );
}
}

View File

@ -0,0 +1,123 @@
/*
* 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.sql.Types;
import java.time.Instant;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.descriptor.java.TemporalJavaTypeDescriptor;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
/**
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = DatePrecisionTests.EntityOfDates.class )
@SessionFactory
public class DatePrecisionTests {
@Test
public void verifyMapping(SessionFactoryScope scope) {
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityOfDates.class );
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "dateAsTimestamp" );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
final TemporalJavaTypeDescriptor jtd = (TemporalJavaTypeDescriptor) jdbcMapping.getJavaTypeDescriptor();
assertThat( jtd, is( attribute.getJavaTypeDescriptor() ) );
assertThat( jtd.getJavaTypeClass(), equalTo( java.util.Date.class ) );
assertThat( jtd.getPrecision(), equalTo( TemporalType.TIMESTAMP ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.TIMESTAMP ) );
}
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "dateAsDate" );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
final TemporalJavaTypeDescriptor jtd = (TemporalJavaTypeDescriptor) jdbcMapping.getJavaTypeDescriptor();
assertThat( jtd, is( attribute.getJavaTypeDescriptor() ) );
assertThat( jtd.getJavaTypeClass(), equalTo( java.util.Date.class ) );
assertThat( jtd.getPrecision(), equalTo( TemporalType.DATE ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.DATE ) );
}
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "dateAsTime" );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
final TemporalJavaTypeDescriptor jtd = (TemporalJavaTypeDescriptor) jdbcMapping.getJavaTypeDescriptor();
assertThat( jtd, is( attribute.getJavaTypeDescriptor() ) );
assertThat( jtd.getJavaTypeClass(), equalTo( java.util.Date.class ) );
assertThat( jtd.getPrecision(), equalTo( TemporalType.TIME ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.TIME ) );
}
// check persistence operations
scope.inTransaction(
(session) -> {
session.persist(
new EntityOfDates(
1,
Date.from( Instant.now() ),
Date.from( Instant.now() ),
Date.from( Instant.now() )
)
);
}
);
scope.inTransaction(
(session) -> {
session.find( EntityOfDates.class, 1 );
}
);
}
@Entity( name = "EntityWithTimestamp" )
public static class EntityOfDates {
@Id
private Integer id;
//tag::basic-temporal-example[]
// mapped as TIMESTAMP by default
Date dateAsTimestamp;
// explicitly mapped as DATE
@Temporal( TemporalType.DATE )
Date dateAsDate;
// explicitly mapped as TIME
@Temporal( TemporalType.TIME )
Date dateAsTime;
//end::basic-temporal-example[]
public EntityOfDates() {
}
public EntityOfDates(Integer id, Date dateAsTimestamp, Date dateAsDate, Date dateAsTime) {
this.id = id;
this.dateAsTimestamp = dateAsTimestamp;
this.dateAsDate = dateAsDate;
this.dateAsTime = dateAsTime;
}
}
}

View File

@ -0,0 +1,108 @@
/*
* 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.sql.Types;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.isOneOf;
/**
* Tests for mapping `double` values
*
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = DoubleMappingTests.EntityOfDoubles.class )
@SessionFactory
public class DoubleMappingTests {
@Test
public void testMappings(SessionFactoryScope scope) {
// first, verify the type selections...
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityOfDoubles.class );
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "wrapper" );
assertThat( attribute.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Double.class ) );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Double.class ) );
assertThat(
jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(),
isOneOf( Types.DOUBLE, Types.FLOAT, Types.REAL, Types.NUMERIC )
);
}
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "primitive" );
assertThat( attribute.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Double.class ) );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Double.class ) );
assertThat(
jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(),
isOneOf( Types.DOUBLE, Types.FLOAT, Types.REAL, Types.NUMERIC )
);
}
// and try to use the mapping
scope.inTransaction(
(session) -> session.persist( new EntityOfDoubles( 1, 3.0, 5.0 ) )
);
scope.inTransaction(
(session) -> session.get( EntityOfDoubles.class, 1 )
);
}
@AfterEach
public void dropData(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> session.createQuery( "delete EntityOfDoubles" ).executeUpdate()
);
}
@Entity( name = "EntityOfDoubles" )
@Table( name = "EntityOfDoubles" )
public static class EntityOfDoubles {
@Id
Integer id;
//tag::basic-double-example-implicit[]
// these will be mapped using DOUBLE, FLOAT, REAL or NUMERIC
// depending on the capabilities of the database
Double wrapper;
double primitive;
//end::basic-double-example-implicit[]
public EntityOfDoubles() {
}
public EntityOfDoubles(Integer id, Double wrapper, double primitive) {
this.id = id;
this.wrapper = wrapper;
this.primitive = primitive;
}
}
}

View File

@ -0,0 +1,75 @@
/*
* 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.sql.Types;
import java.time.Duration;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
/**
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = DurationMappingTests.EntityWithDuration.class )
@SessionFactory
public class DurationMappingTests {
@Test
public void verifyMappings(SessionFactoryScope scope) {
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityWithDuration.class );
final BasicAttributeMapping duration = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "duration" );
final JdbcMapping jdbcMapping = duration.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Duration.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.NUMERIC ) );
scope.inTransaction(
(session) -> {
session.persist( new EntityWithDuration( 1, Duration.ofHours( 3 ) ) );
}
);
scope.inTransaction(
(session) -> session.find( EntityWithDuration.class, 1 )
);
}
@Entity( name = "EntityWithDuration" )
@Table( name = "EntityWithDuration" )
public static class EntityWithDuration {
@Id
private Integer id;
//tag::basic-duration-example[]
private Duration duration;
//end::basic-duration-example[]
public EntityWithDuration() {
}
public EntityWithDuration(Integer id, Duration duration) {
this.id = id;
this.duration = duration;
}
}
}

View File

@ -0,0 +1,107 @@
/*
* 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.sql.Types;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.isOneOf;
/**
* Tests for mapping `double` values
*
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = FloatMappingTests.EntityOfFloats.class )
@SessionFactory
public class FloatMappingTests {
@Test
public void testMappings(SessionFactoryScope scope) {
// first, verify the type selections...
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityOfFloats.class );
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "wrapper" );
assertThat( attribute.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Float.class ) );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Float.class ) );
assertThat(
jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(),
isOneOf( Types.FLOAT, Types.REAL, Types.NUMERIC )
);
}
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "primitive" );
assertThat( attribute.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Float.class ) );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Float.class ) );
assertThat(
jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(),
isOneOf( Types.FLOAT, Types.REAL, Types.NUMERIC )
);
}
// and try to use the mapping
scope.inTransaction(
(session) -> session.persist( new EntityOfFloats( 1, 3.0F, 5.0F ) )
);
scope.inTransaction(
(session) -> session.get( EntityOfFloats.class, 1 )
);
}
@AfterEach
public void dropData(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> session.createQuery( "delete EntityOfFloats" ).executeUpdate()
);
}
@Entity( name = "EntityOfFloats" )
@Table( name = "EntityOfFloats" )
public static class EntityOfFloats {
@Id
Integer id;
//tag::basic-float-example-implicit[]
// these will be mapped using FLOAT, REAL or NUMERIC
// depending on the capabilities of the database
Float wrapper;
float primitive;
//end::basic-float-example-implicit[]
public EntityOfFloats() {
}
public EntityOfFloats(Integer id, Float wrapper, float primitive) {
this.id = id;
this.wrapper = wrapper;
this.primitive = primitive;
}
}
}

View File

@ -0,0 +1,76 @@
/*
* 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.sql.Types;
import java.time.Duration;
import java.time.Instant;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
/**
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = InstantMappingTests.EntityWithInstant.class )
@SessionFactory
public class InstantMappingTests {
@Test
public void verifyMappings(SessionFactoryScope scope) {
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityWithInstant.class );
final BasicAttributeMapping duration = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "instant" );
final JdbcMapping jdbcMapping = duration.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Instant.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.TIMESTAMP ) );
scope.inTransaction(
(session) -> {
session.persist( new EntityWithInstant( 1, Instant.now() ) );
}
);
scope.inTransaction(
(session) -> session.find( EntityWithInstant.class, 1 )
);
}
@Entity( name = "EntityWithInstant" )
@Table( name = "EntityWithInstant" )
public static class EntityWithInstant {
@Id
private Integer id;
//tag::basic-instant-example[]
// mapped as TIMESTAMP
private Instant instant;
//end::basic-instant-example[]
public EntityWithInstant() {
}
public EntityWithInstant(Integer id, Instant instant) {
this.id = id;
this.instant = instant;
}
}
}

View File

@ -0,0 +1,100 @@
/*
* 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.sql.Types;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
/**
* Tests for mapping `short` values
*
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = IntegerMappingTests.EntityOfIntegers.class )
@SessionFactory
public class IntegerMappingTests {
@Test
public void testMappings(SessionFactoryScope scope) {
// first, verify the type selections...
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityOfIntegers.class );
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "wrapper" );
assertThat( attribute.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Integer.class ) );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Integer.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), is( Types.INTEGER ) );
}
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "primitive" );
assertThat( attribute.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Integer.class ) );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Integer.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), is( Types.INTEGER ) );
}
// and try to use the mapping
scope.inTransaction(
(session) -> session.persist( new EntityOfIntegers( 1, 3, 5 ) )
);
scope.inTransaction(
(session) -> session.get( EntityOfIntegers.class, 1 )
);
}
@AfterEach
public void dropData(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> session.createQuery( "delete EntityOfIntegers" ).executeUpdate()
);
}
@Entity( name = "EntityOfIntegers" )
@Table( name = "EntityOfIntegers" )
public static class EntityOfIntegers {
@Id
Integer id;
//tag::basic-integer-example-implicit[]
// these will both be mapped using INTEGER
Integer wrapper;
int primitive;
//end::basic-integer-example-implicit[]
public EntityOfIntegers() {
}
public EntityOfIntegers(Integer id, Integer wrapper, int primitive) {
this.id = id;
this.wrapper = wrapper;
this.primitive = primitive;
}
}
}

View File

@ -0,0 +1,76 @@
/*
* 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.sql.Types;
import java.time.Instant;
import java.time.LocalDate;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
/**
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = LocalDateMappingTests.EntityWithLocalDate.class )
@SessionFactory
public class LocalDateMappingTests {
@Test
public void verifyMappings(SessionFactoryScope scope) {
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityWithLocalDate.class );
final BasicAttributeMapping duration = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "localDate" );
final JdbcMapping jdbcMapping = duration.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( LocalDate.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.DATE ) );
scope.inTransaction(
(session) -> {
session.persist( new EntityWithLocalDate( 1, LocalDate.now() ) );
}
);
scope.inTransaction(
(session) -> session.find( EntityWithLocalDate.class, 1 )
);
}
@Entity( name = "EntityWithLocalDate" )
@Table( name = "EntityWithLocalDate" )
public static class EntityWithLocalDate {
@Id
private Integer id;
//tag::basic-localDate-example[]
// mapped as DATE
private LocalDate localDate;
//end::basic-localDate-example[]
public EntityWithLocalDate() {
}
public EntityWithLocalDate(Integer id, LocalDate localDate) {
this.id = id;
this.localDate = localDate;
}
}
}

View File

@ -0,0 +1,75 @@
/*
* 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.sql.Types;
import java.time.LocalDateTime;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
/**
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = LocalDateTimeMappingTests.EntityWithLocalDateTime.class )
@SessionFactory
public class LocalDateTimeMappingTests {
@Test
public void verifyMappings(SessionFactoryScope scope) {
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityWithLocalDateTime.class );
final BasicAttributeMapping duration = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "localDateTime" );
final JdbcMapping jdbcMapping = duration.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( LocalDateTime.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.TIMESTAMP ) );
scope.inTransaction(
(session) -> {
session.persist( new EntityWithLocalDateTime( 1, LocalDateTime.now() ) );
}
);
scope.inTransaction(
(session) -> session.find( EntityWithLocalDateTime.class, 1 )
);
}
@Entity( name = "EntityWithLocalDateTime" )
@Table( name = "EntityWithLocalDateTime" )
public static class EntityWithLocalDateTime {
@Id
private Integer id;
//tag::basic-localDateTime-example[]
// mapped as TIMESTAMP
private LocalDateTime localDateTime;
//end::basic-localDateTime-example[]
public EntityWithLocalDateTime() {
}
public EntityWithLocalDateTime(Integer id, LocalDateTime localDateTime) {
this.id = id;
this.localDateTime = localDateTime;
}
}
}

View File

@ -0,0 +1,77 @@
/*
* 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.sql.Types;
import java.time.LocalTime;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
/**
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = LocalTimeMappingTests.EntityWithLocalTime.class )
@SessionFactory
public class LocalTimeMappingTests {
@Test
public void verifyMappings(SessionFactoryScope scope) {
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityWithLocalTime.class );
final BasicAttributeMapping duration = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "localTime" );
final JdbcMapping jdbcMapping = duration.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( LocalTime.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.TIME ) );
scope.inTransaction(
(session) -> {
session.persist( new EntityWithLocalTime( 1, LocalTime.now() ) );
}
);
scope.inTransaction(
(session) -> session.find( EntityWithLocalTime.class, 1 )
);
}
@Entity( name = "EntityWithLocalTime" )
@Table( name = "EntityWithLocalTime" )
public static class EntityWithLocalTime {
@Id
private Integer id;
@Column( name = "`localTime`")
//tag::basic-localTime-example[]
// mapped as TIME
private LocalTime localTime;
//end::basic-localTime-example[]
public EntityWithLocalTime() {
}
public EntityWithLocalTime(Integer id, LocalTime localTime) {
this.id = id;
this.localTime = localTime;
}
}
}

View File

@ -0,0 +1,76 @@
/*
* 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.sql.Types;
import java.util.Currency;
import java.util.Locale;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
/**
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = LocaleMappingTests.EntityWithLocale.class )
@SessionFactory
public class LocaleMappingTests {
@Test
public void verifyMappings(SessionFactoryScope scope) {
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityWithLocale.class );
final BasicAttributeMapping duration = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "locale" );
final JdbcMapping jdbcMapping = duration.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Locale.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.VARCHAR ) );
scope.inTransaction(
(session) -> {
session.persist( new EntityWithLocale( 1, Locale.US ) );
}
);
scope.inTransaction(
(session) -> session.find( EntityWithLocale.class, 1 )
);
}
@Entity( name = "EntityWithLocale" )
@Table( name = "EntityWithLocale" )
public static class EntityWithLocale {
@Id
private Integer id;
//tag::basic-Locale-example[]
// mapped as VARCHAR
private Locale locale;
//end::basic-Locale-example[]
public EntityWithLocale() {
}
public EntityWithLocale(Integer id, Locale locale) {
this.id = id;
this.locale = locale;
}
}
}

View File

@ -0,0 +1,100 @@
/*
* 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.sql.Types;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
/**
* Tests for mapping `short` values
*
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = LongMappingTests.EntityOfLongs.class )
@SessionFactory
public class LongMappingTests {
@Test
public void testMappings(SessionFactoryScope scope) {
// first, verify the type selections...
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityOfLongs.class );
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "wrapper" );
assertThat( attribute.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Long.class ) );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Long.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), is( Types.BIGINT ) );
}
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "primitive" );
assertThat( attribute.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Long.class ) );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Long.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), is( Types.BIGINT ) );
}
// and try to use the mapping
scope.inTransaction(
(session) -> session.persist( new EntityOfLongs( 1, 3L, 5L ) )
);
scope.inTransaction(
(session) -> session.get( EntityOfLongs.class, 1 )
);
}
@AfterEach
public void dropData(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> session.createQuery( "delete EntityOfLongs" ).executeUpdate()
);
}
@Entity( name = "EntityOfLongs" )
@Table( name = "EntityOfLongs" )
public static class EntityOfLongs {
@Id
Integer id;
//tag::basic-long-example-implicit[]
// these will both be mapped using BIGINT
Long wrapper;
long primitive;
//end::basic-long-example-implicit[]
public EntityOfLongs() {
}
public EntityOfLongs(Integer id, Long wrapper, long primitive) {
this.id = id;
this.wrapper = wrapper;
this.primitive = primitive;
}
}
}

View File

@ -11,12 +11,8 @@ import javax.persistence.Id;
import javax.persistence.Lob;
import org.hibernate.annotations.Nationalized;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.dialect.MySQL5Dialect;
import org.hibernate.dialect.PostgreSQL81Dialect;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.SkipForDialect;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
@ -25,14 +21,6 @@ import static org.junit.Assert.assertArrayEquals;
/**
* @author Vlad Mihalcea
*/
@SkipForDialect(
value = {
PostgreSQL81Dialect.class,
MySQL5Dialect.class,
DB2Dialect.class
},
comment = "@see https://hibernate.atlassian.net/browse/HHH-10693 and https://hibernate.atlassian.net/browse/HHH-10695 and https://hibernate.atlassian.net/browse/HHH-10473"
)
public class NClobCharArrayTest extends BaseEntityManagerFunctionalTestCase {
@Override

View File

@ -11,12 +11,10 @@ import javax.persistence.Id;
import javax.persistence.Lob;
import org.hibernate.annotations.Nationalized;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.dialect.MySQL5Dialect;
import org.hibernate.dialect.PostgreSQL81Dialect;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.SkipForDialect;
import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.RequiresDialectFeature;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
@ -25,14 +23,6 @@ import static org.junit.Assert.assertEquals;
/**
* @author Vlad Mihalcea
*/
@SkipForDialect(
value = {
PostgreSQL81Dialect.class,
MySQL5Dialect.class,
DB2Dialect.class
},
comment = "@see https://hibernate.atlassian.net/browse/HHH-10693 and https://hibernate.atlassian.net/browse/HHH-10695 and https://hibernate.atlassian.net/browse/HHH-10473"
)
public class NClobStringTest extends BaseEntityManagerFunctionalTestCase {
@Override

View File

@ -15,89 +15,71 @@ import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Lob;
import org.hibernate.Session;
import org.hibernate.annotations.Nationalized;
import org.hibernate.dialect.AbstractHANADialect;
import org.hibernate.dialect.CockroachDialect;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.dialect.MySQL5Dialect;
import org.hibernate.dialect.PostgreSQL81Dialect;
import org.hibernate.engine.jdbc.NClobProxy;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.SkipForDialect;
import org.junit.Test;
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
import org.hibernate.testing.orm.junit.Jpa;
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
import org.junit.jupiter.api.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
/**
* @author Vlad Mihalcea
*/
@SkipForDialect(
value = {
PostgreSQL81Dialect.class,
MySQL5Dialect.class,
AbstractHANADialect.class,
CockroachDialect.class,
DB2Dialect.class
},
@Jpa(annotatedClasses = NClobTest.Product.class)
@RequiresDialectFeature(
feature = DialectFeatureChecks.SupportsNationalizedDataTypes.class,
comment = "@see https://hibernate.atlassian.net/browse/HHH-10693 and https://hibernate.atlassian.net/browse/HHH-10695 and https://hibernate.atlassian.net/browse/HHH-10473"
)
public class NClobTest extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Product.class
};
}
public class NClobTest {
@Test
public void test() {
Integer productId = doInJPA( this::entityManagerFactory, entityManager -> {
Session session = entityManager.unwrap( Session.class );
public void test(EntityManagerFactoryScope scope) {
scope.inTransaction(
(entityManager) -> {
//tag::basic-nclob-persist-example[]
String warranty = "My product warranty";
//tag::basic-nclob-persist-example[]
String warranty = "My product warranty";
final Product product = new Product();
product.setId( 1 );
product.setName( "Mobile phone" );
final Product product = new Product();
product.setId( 1 );
product.setName( "Mobile phone" );
product.setWarranty( NClobProxy.generateProxy( warranty ) );
product.setWarranty( NClobProxy.generateProxy( warranty ) );
entityManager.persist( product );
//end::basic-nclob-persist-example[]
return product.getId();
} );
doInJPA( this::entityManagerFactory, entityManager -> {
try {
//tag::basic-nclob-find-example[]
Product product = entityManager.find( Product.class, productId );
try (Reader reader = product.getWarranty().getCharacterStream()) {
assertEquals( "My product warranty", toString( reader ) );
entityManager.persist( product );
//end::basic-nclob-persist-example[]
}
//end::basic-nclob-find-example[]
}
catch (Exception e) {
fail( e.getMessage() );
}
} );
);
scope.inTransaction(
(entityManager) -> {
try {
//tag::basic-nclob-find-example[]
Product product = entityManager.find( Product.class, 1 );
try ( Reader reader = product.getWarranty().getCharacterStream() ) {
assertEquals( "My product warranty", toString( reader ) );
}
//end::basic-nclob-find-example[]
}
catch (Exception e) {
fail( e.getMessage() );
}
}
);
}
private String toString(Reader reader) throws IOException {
BufferedReader bufferedReader = new BufferedReader( reader);
BufferedReader bufferedReader = new BufferedReader( reader );
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int result = bufferedReader.read();
while(result != -1) {
byteArrayOutputStream.write((byte) result);
while ( result != -1 ) {
byteArrayOutputStream.write( (byte) result );
result = bufferedReader.read();
}
@ -122,7 +104,7 @@ public class NClobTest extends BaseEntityManagerFunctionalTestCase {
//Getters and setters are omitted for brevity
//end::basic-nclob-example[]
//end::basic-nclob-example[]
public Integer getId() {
return id;
}
@ -150,4 +132,4 @@ public class NClobTest extends BaseEntityManagerFunctionalTestCase {
//tag::basic-nclob-example[]
}
//end::basic-nclob-example[]
}
}

View File

@ -0,0 +1,78 @@
/*
* 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.sql.Types;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.isOneOf;
/**
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = OffsetDateTimeMappingTests.EntityWithOffsetDateTime.class )
@SessionFactory
public class OffsetDateTimeMappingTests {
@Test
public void verifyMappings(SessionFactoryScope scope) {
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityWithOffsetDateTime.class );
final BasicAttributeMapping attributeMapping = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "offsetDateTime" );
final JdbcMapping jdbcMapping = attributeMapping.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( OffsetDateTime.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), isOneOf( Types.TIMESTAMP, Types.TIMESTAMP_WITH_TIMEZONE ) );
scope.inTransaction(
(session) -> {
session.persist( new EntityWithOffsetDateTime( 1, OffsetDateTime.now() ) );
}
);
scope.inTransaction(
(session) -> session.find( EntityWithOffsetDateTime.class, 1 )
);
}
@Entity( name = "EntityWithOffsetDateTime" )
@Table( name = "EntityWithOffsetDateTime" )
public static class EntityWithOffsetDateTime {
@Id
private Integer id;
//tag::basic-OffsetDateTime-example[]
// mapped as TIMESTAMP or TIMESTAMP_WITH_TIMEZONE
private OffsetDateTime offsetDateTime;
//end::basic-OffsetDateTime-example[]
public EntityWithOffsetDateTime() {
}
public EntityWithOffsetDateTime(Integer id, OffsetDateTime offsetDateTime) {
this.id = id;
this.offsetDateTime = offsetDateTime;
}
}
}

View File

@ -0,0 +1,77 @@
/*
* 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.sql.Types;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.isOneOf;
/**
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = OffsetTimeMappingTests.EntityWithOffsetTime.class )
@SessionFactory
public class OffsetTimeMappingTests {
@Test
public void verifyMappings(SessionFactoryScope scope) {
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityWithOffsetTime.class );
final BasicAttributeMapping attributeMapping = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "offsetTime" );
final JdbcMapping jdbcMapping = attributeMapping.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( OffsetTime.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), isOneOf( Types.TIME, Types.TIME_WITH_TIMEZONE ) );
scope.inTransaction(
(session) -> {
session.persist( new EntityWithOffsetTime( 1, OffsetTime.now() ) );
}
);
scope.inTransaction(
(session) -> session.find( EntityWithOffsetTime.class, 1 )
);
}
@Entity( name = "EntityWithOffsetTime" )
@Table( name = "EntityWithOffsetTime" )
public static class EntityWithOffsetTime {
@Id
private Integer id;
//tag::basic-offsetTime-example[]
// mapped as TIME or TIME_WITH_TIMEZONE
private OffsetTime offsetTime;
//end::basic-offsetTime-example[]
public EntityWithOffsetTime() {
}
public EntityWithOffsetTime(Integer id, OffsetTime offsetTime) {
this.id = id;
this.offsetTime = offsetTime;
}
}
}

View File

@ -0,0 +1,100 @@
/*
* 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.sql.Types;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
/**
* Tests for mapping `short` values
*
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = ShortMappingTests.EntityOfShorts.class )
@SessionFactory
public class ShortMappingTests {
@Test
public void testMappings(SessionFactoryScope scope) {
// first, verify the type selections...
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityOfShorts.class );
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "wrapper" );
assertThat( attribute.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Short.class ) );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Short.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), is( Types.SMALLINT ) );
}
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "primitive" );
assertThat( attribute.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Short.class ) );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Short.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), is( Types.SMALLINT ) );
}
// and try to use the mapping
scope.inTransaction(
(session) -> session.persist( new EntityOfShorts( 1, (short) 3, (short) 5 ) )
);
scope.inTransaction(
(session) -> session.get( EntityOfShorts.class, 1 )
);
}
@AfterEach
public void dropData(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> session.createQuery( "delete EntityOfShorts" ).executeUpdate()
);
}
@Entity( name = "EntityOfShorts" )
@Table( name = "EntityOfShorts" )
public static class EntityOfShorts {
@Id
Integer id;
//tag::basic-short-example-implicit[]
// these will both be mapped using SMALLINT
Short wrapper;
short primitive;
//end::basic-short-example-implicit[]
public EntityOfShorts() {
}
public EntityOfShorts(Integer id, Short wrapper, short primitive) {
this.id = id;
this.wrapper = wrapper;
this.primitive = primitive;
}
}
}

View File

@ -0,0 +1,101 @@
/*
* 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.sql.Types;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
/**
* Tests for mapping `double` values
*
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = StringMappingTests.EntityOfStrings.class )
@SessionFactory
public class StringMappingTests {
@Test
public void testMappings(SessionFactoryScope scope) {
// first, verify the type selections...
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityOfStrings.class );
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "string" );
assertThat( attribute.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( String.class ) );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( String.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.VARCHAR ) );
}
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "clobString" );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( String.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.CLOB ) );
}
// and try to use the mapping
scope.inTransaction(
(session) -> session.persist( new EntityOfStrings( 1, "string", "clob" ) )
);
scope.inTransaction(
(session) -> session.get( EntityOfStrings.class, 1 )
);
}
@AfterEach
public void dropData(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> session.createQuery( "delete EntityOfStrings" ).executeUpdate()
);
}
@Entity( name = "EntityOfStrings" )
@Table( name = "EntityOfStrings" )
public static class EntityOfStrings {
@Id
Integer id;
//tag::basic-string-example[]
// will be mapped using VARCHAR
String string;
// will be mapped using CLOB
@Lob
String clobString;
//end::basic-string-example[]
public EntityOfStrings() {
}
public EntityOfStrings(Integer id, String string, String clobString) {
this.id = id;
this.string = string;
this.clobString = clobString;
}
}
}

View File

@ -0,0 +1,106 @@
/*
* 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 javax.persistence.Lob;
import javax.persistence.Table;
import org.hibernate.annotations.Nationalized;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.NationalizationSupport;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
/**
* Tests for mapping `double` values
*
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = StringNationalizedMappingTests.EntityOfStrings.class )
@SessionFactory
public class StringNationalizedMappingTests {
@Test
public void testMappings(SessionFactoryScope scope) {
// first, verify the type selections...
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityOfStrings.class );
final Dialect dialect = scope.getSessionFactory().getJdbcServices().getDialect();
final NationalizationSupport nationalizationSupport = dialect.getNationalizationSupport();
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "nstring" );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( String.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( nationalizationSupport.getVarcharVariantCode() ) );
}
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "nclobString" );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( String.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( nationalizationSupport.getClobVariantCode() ) );
}
// and try to use the mapping
scope.inTransaction(
(session) -> session.persist( new EntityOfStrings( 1, "nstring", "nclob" ) )
);
scope.inTransaction(
(session) -> session.get( EntityOfStrings.class, 1 )
);
}
@AfterEach
public void dropData(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> session.createQuery( "delete EntityOfStrings" ).executeUpdate()
);
}
@Entity( name = "EntityOfStrings" )
@Table( name = "EntityOfStrings" )
public static class EntityOfStrings {
@Id
Integer id;
//tag::basic-nstring-example[]
// will be mapped using NVARCHAR
@Nationalized
String nstring;
// will be mapped using NCLOB
@Lob
@Nationalized
String nclobString;
//end::basic-nstring-example[]
public EntityOfStrings() {
}
public EntityOfStrings(Integer id, String nstring, String nclobString) {
this.id = id;
this.nstring = nstring;
this.nclobString = nclobString;
}
}
}

View File

@ -16,84 +16,163 @@ import javax.persistence.Table;
import org.hibernate.annotations.Subselect;
import org.hibernate.annotations.Synchronize;
import org.hibernate.dialect.DerbyDialect;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.SkipForDialect;
import org.junit.Test;
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
import org.hibernate.testing.orm.junit.Jpa;
import org.hibernate.testing.orm.junit.NotImplementedYet;
import org.hibernate.testing.orm.junit.SkipForDialect;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertEquals;
/**
* @author Vlad Mihalcea
*/
@SkipForDialect(value = DerbyDialect.class, comment = "Derby doesn't support a CONCAT function")
public class SubselectTest extends BaseEntityManagerFunctionalTestCase {
@Jpa(
annotatedClasses = {
SubselectTest.Client.class,
SubselectTest.Account.class,
SubselectTest.AccountTransaction.class,
SubselectTest.AccountSummary.class
}
)
@SkipForDialect( dialectClass = DerbyDialect.class, reason = "Derby doesn't support a CONCAT function" )
public class SubselectTest {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Client.class,
Account.class,
AccountTransaction.class,
AccountSummary.class
};
@Test
public void testNormalLifecycle(EntityManagerFactoryScope scope) {
// same as `#testRefreshLifecycle` except that here we do not rely on
// `Session#refresh` which atm in 6.0 dev does not appear to work properly
// at least in this scenario
// create the entity
scope.inTransaction(
(entityManager) -> {
Client client = new Client();
client.setId( 1L );
client.setFirstName( "John" );
client.setLastName( "Doe" );
entityManager.persist( client );
Account account = new Account();
account.setId( 1L );
account.setClient( client );
account.setDescription( "Checking account" );
entityManager.persist( account );
AccountTransaction transaction = new AccountTransaction();
transaction.setAccount( account );
transaction.setDescription( "Salary" );
transaction.setCents( 100 * 7000 );
entityManager.persist( transaction );
}
);
// load the entity, verify its state and add a new transaction (thereby updating the calculated balance)
scope.inTransaction(
(entityManager) -> {
AccountSummary summary = entityManager.createQuery(
"select s " +
"from AccountSummary s " +
"where s.id = :id", AccountSummary.class)
.setParameter( "id", 1L )
.getSingleResult();
assertEquals( "John Doe", summary.getClientName() );
assertEquals( 100 * 7000, summary.getBalance() );
AccountTransaction transaction = new AccountTransaction();
transaction.setAccount( entityManager.getReference( Account.class, 1L ) );
transaction.setDescription( "Shopping" );
transaction.setCents( -100 * 2200 );
entityManager.persist( transaction );
}
);
// load the AccountSummary and verify the updated balance
scope.inTransaction(
(entityManager) -> {
AccountSummary summary = entityManager.find( AccountSummary.class, 1L );
assertEquals( "John Doe", summary.getClientName() );
assertEquals( 100 * 4800, summary.getBalance() );
}
);
}
@Test
public void testLifecycle() {
@NotImplementedYet(
reason = "Refreshing a managed-entity does not work - https://trello.com/c/QAKC08JT/230-refresh-does-not-work-with-managed-entity-the-state-is-not-refreshed",
strict = false
)
public void testRefreshLifecycle(EntityManagerFactoryScope scope) {
//tag::mapping-Subselect-entity-find-example[]
doInJPA( this::entityManagerFactory, entityManager -> {
Client client = new Client();
client.setId( 1L );
client.setFirstName( "John" );
client.setLastName( "Doe" );
entityManager.persist( client );
scope.inTransaction(
(entityManager) -> {
Client client = new Client();
client.setId( 1L );
client.setFirstName( "John" );
client.setLastName( "Doe" );
entityManager.persist( client );
Account account = new Account();
account.setId( 1L );
account.setClient( client );
account.setDescription( "Checking account" );
entityManager.persist( account );
Account account = new Account();
account.setId( 1L );
account.setClient( client );
account.setDescription( "Checking account" );
entityManager.persist( account );
AccountTransaction transaction = new AccountTransaction();
transaction.setAccount( account );
transaction.setDescription( "Salary" );
transaction.setCents( 100 * 7000 );
entityManager.persist( transaction );
AccountTransaction transaction = new AccountTransaction();
transaction.setAccount( account );
transaction.setDescription( "Salary" );
transaction.setCents( 100 * 7000 );
entityManager.persist( transaction );
AccountSummary summary = entityManager.createQuery(
"select s " +
"from AccountSummary s " +
"where s.id = :id", AccountSummary.class)
.setParameter( "id", account.getId() )
.getSingleResult();
AccountSummary summary = entityManager.createQuery(
"select s " +
"from AccountSummary s " +
"where s.id = :id", AccountSummary.class)
.setParameter( "id", account.getId() )
.getSingleResult();
assertEquals( "John Doe", summary.getClientName() );
assertEquals( 100 * 7000, summary.getBalance() );
} );
assertEquals( "John Doe", summary.getClientName() );
assertEquals( 100 * 7000, summary.getBalance() );
}
);
//end::mapping-Subselect-entity-find-example[]
//tag::mapping-Subselect-entity-refresh-example[]
doInJPA( this::entityManagerFactory, entityManager -> {
AccountSummary summary = entityManager.find( AccountSummary.class, 1L );
assertEquals( "John Doe", summary.getClientName() );
assertEquals( 100 * 7000, summary.getBalance() );
scope.inTransaction(
(entityManager) -> {
AccountSummary summary = entityManager.find( AccountSummary.class, 1L );
assertEquals( "John Doe", summary.getClientName() );
assertEquals( 100 * 7000, summary.getBalance() );
AccountTransaction transaction = new AccountTransaction();
transaction.setAccount( entityManager.getReference( Account.class, 1L ) );
transaction.setDescription( "Shopping" );
transaction.setCents( -100 * 2200 );
entityManager.persist( transaction );
entityManager.flush();
entityManager.refresh( summary );
assertEquals( 100 * 4800, summary.getBalance() );
} );
AccountTransaction transaction = new AccountTransaction();
transaction.setAccount( entityManager.getReference( Account.class, 1L ) );
transaction.setDescription( "Shopping" );
transaction.setCents( -100 * 2200 );
entityManager.persist( transaction );
entityManager.flush();
entityManager.refresh( summary );
assertEquals( 100 * 4800, summary.getBalance() );
}
);
//end::mapping-Subselect-entity-refresh-example[]
}
@AfterEach
public void dropTestData(EntityManagerFactoryScope scope) {
scope.inTransaction(
(entityManager) -> {
entityManager.createQuery( "delete AccountTransaction" ).executeUpdate();
entityManager.createQuery( "delete Account" ).executeUpdate();
entityManager.createQuery( "delete Client" ).executeUpdate();
}
);
}
//tag::mapping-Subselect-example[]
@Entity(name = "Client")
@Table(name = "client")

View File

@ -0,0 +1,77 @@
/*
* 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.sql.Types;
import java.time.Duration;
import java.time.ZoneId;
import java.util.TimeZone;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
/**
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = TimeZoneMappingTests.EntityWithTimeZone.class )
@SessionFactory
public class TimeZoneMappingTests {
@Test
public void verifyMappings(SessionFactoryScope scope) {
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityWithTimeZone.class );
final BasicAttributeMapping duration = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "timeZone" );
final JdbcMapping jdbcMapping = duration.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( TimeZone.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.VARCHAR ) );
scope.inTransaction(
(session) -> {
session.persist( new EntityWithTimeZone( 1, TimeZone.getDefault() ) );
}
);
scope.inTransaction(
(session) -> session.find( EntityWithTimeZone.class, 1 )
);
}
@Entity( name = "EntityWithTimeZone" )
@Table( name = "EntityWithTimeZone" )
public static class EntityWithTimeZone {
@Id
private Integer id;
//tag::basic-timeZone-example[]
// mapped as VARCHAR
private TimeZone timeZone;
//end::basic-timeZone-example[]
public EntityWithTimeZone() {
}
public EntityWithTimeZone(Integer id, TimeZone timeZone) {
this.id = id;
this.timeZone = timeZone;
}
}
}

View File

@ -0,0 +1,76 @@
/*
* 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.sql.Types;
import java.time.ZoneOffset;
import java.util.TimeZone;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
/**
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = ZoneOffsetMappingTests.EntityWithZoneOffset.class )
@SessionFactory
public class ZoneOffsetMappingTests {
@Test
public void verifyMappings(SessionFactoryScope scope) {
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityWithZoneOffset.class );
final BasicAttributeMapping duration = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "zoneOffset" );
final JdbcMapping jdbcMapping = duration.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( ZoneOffset.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.VARCHAR ) );
scope.inTransaction(
(session) -> {
session.persist( new EntityWithZoneOffset( 1, ZoneOffset.from( ZoneOffset.MIN ) ) );
}
);
scope.inTransaction(
(session) -> session.find( EntityWithZoneOffset.class, 1 )
);
}
@Entity( name = "EntityWithZoneOffset" )
@Table( name = "EntityWithZoneOffset" )
public static class EntityWithZoneOffset {
@Id
private Integer id;
//tag::basic-ZoneOffset-example[]
// mapped as VARCHAR
private ZoneOffset zoneOffset;
//end::basic-ZoneOffset-example[]
public EntityWithZoneOffset() {
}
public EntityWithZoneOffset(Integer id, ZoneOffset zoneOffset) {
this.id = id;
this.zoneOffset = zoneOffset;
}
}
}

View File

@ -0,0 +1,77 @@
/*
* 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.sql.Types;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.isOneOf;
/**
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = ZonedDateTimeMappingTests.EntityWithZonedDateTime.class )
@SessionFactory
public class ZonedDateTimeMappingTests {
@Test
public void verifyMappings(SessionFactoryScope scope) {
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityWithZonedDateTime.class );
final BasicAttributeMapping attributeMapping = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "zonedDateTime" );
final JdbcMapping jdbcMapping = attributeMapping.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( ZonedDateTime.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), isOneOf( Types.TIMESTAMP, Types.TIMESTAMP_WITH_TIMEZONE ) );
scope.inTransaction(
(session) -> {
session.persist( new EntityWithZonedDateTime( 1, ZonedDateTime.now() ) );
}
);
scope.inTransaction(
(session) -> session.find( EntityWithZonedDateTime.class, 1 )
);
}
@Entity( name = "EntityWithZonedDateTime" )
@Table( name = "EntityWithZonedDateTime" )
public static class EntityWithZonedDateTime {
@Id
private Integer id;
//tag::basic-ZonedDateTime-example[]
// mapped as TIMESTAMP or TIMESTAMP_WITH_TIMEZONE
private ZonedDateTime zonedDateTime;
//end::basic-ZonedDateTime-example[]
public EntityWithZonedDateTime() {
}
public EntityWithZonedDateTime(Integer id, ZonedDateTime zonedDateTime) {
this.id = id;
this.zonedDateTime = zonedDateTime;
}
}
}

View File

@ -344,7 +344,7 @@ class Antlr4Plugin implements Plugin<Project> {
}
}
class Antlr4GenerationTask extends DefaultTask {
abstract class Antlr4GenerationTask extends DefaultTask {
static final String HQL_PCKG = 'org.hibernate.grammars.hql'
static final String IMPORT_SQL_PCKG = 'org.hibernate.grammars.importsql'
static final String GRAPH_PCKG = 'org.hibernate.grammars.graph'

View File

@ -9,13 +9,26 @@ package org.hibernate.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.hibernate.dialect.Dialect;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Marks a character data type (String, Character, character, Clob) as being a nationalized variant
* (NVARCHAR, NCHAR, NCLOB, etc).
* Used to indicate that the annotated character data should be stored with
* nationalization support.
*
* The annotation's affect depends on {@link Dialect#getNationalizationSupport()}
*
* Some databases support storing nationalized data in their "normal" character data types
* (CHAR, VARCHAR, LONGVARCHAR, CLOB). In such cases this annotation is effectively ignored.
* See {@link org.hibernate.dialect.NationalizationSupport#IMPLICIT}
*
* Some databases support storing nationalized data only through the specialized, standard SQL
* variants (NCHAR, NVARCHAR, LONGNVARCHAR, NCLOB). In such cases this annotation will adjust
* the JDBC type code to the specialized variant. See
* {@link org.hibernate.dialect.NationalizationSupport#EXPLICIT}
*
* @author Steve Ebersole
*/

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.boot.model.process.internal;
import java.io.Serializable;
import java.util.function.Function;
import java.util.function.Supplier;
import javax.persistence.EnumType;
@ -19,10 +20,10 @@ import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.model.convert.internal.NamedEnumValueConverter;
import org.hibernate.metamodel.model.convert.internal.OrdinalEnumValueConverter;
import org.hibernate.metamodel.model.domain.AllowableTemporalParameterType;
import org.hibernate.type.AdjustableBasicType;
import org.hibernate.type.BasicType;
import org.hibernate.type.CustomType;
import org.hibernate.type.SerializableType;
import org.hibernate.type.SqlTypeDescriptorIndicatorCapable;
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
import org.hibernate.type.descriptor.java.EnumJavaTypeDescriptor;
import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan;
@ -31,6 +32,7 @@ import org.hibernate.type.descriptor.java.SerializableTypeDescriptor;
import org.hibernate.type.descriptor.java.TemporalJavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
import org.hibernate.type.descriptor.jdbc.ObjectJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.TinyIntTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
@ -76,23 +78,57 @@ public class InferredBasicValueResolver {
explicitJavaType,
explicitJdbcType
);
legacyType = jdbcMapping;
}
else {
// infer the STD
// we need to infer the JdbcTypeDescriptor and use that to build the value-mapping
final JdbcTypeDescriptor inferredJdbcType = explicitJavaType.getRecommendedJdbcType( stdIndicators );
jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve(
explicitJavaType,
inferredJdbcType
);
}
if ( inferredJdbcType instanceof ObjectJdbcTypeDescriptor ) {
// have a "fallback" JDBC type... see if we can decide a better choice
legacyType = jdbcMapping;
if ( explicitJavaType instanceof EnumJavaTypeDescriptor ) {
return fromEnum(
(EnumJavaTypeDescriptor) reflectedJtd,
explicitJavaType,
null,
stdIndicators,
typeConfiguration
);
}
else if ( explicitJavaType instanceof TemporalJavaTypeDescriptor ) {
return fromTemporal(
(TemporalJavaTypeDescriptor) reflectedJtd,
explicitJavaType,
null,
stdIndicators,
typeConfiguration
);
}
else if ( explicitJavaType instanceof SerializableTypeDescriptor || explicitJavaType.getJavaType() instanceof Serializable ) {
legacyType = new SerializableType<>( explicitJavaType );
jdbcMapping = legacyType;
}
else {
jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve(
explicitJavaType,
inferredJdbcType
);
legacyType = jdbcMapping;
}
}
else {
jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve(
explicitJavaType,
inferredJdbcType
);
legacyType = jdbcMapping;
}
}
}
else if ( reflectedJtd != null ) {
// we were able to determine the "reflected java-type"
if ( explicitJdbcType != null ) {
// we also have an explicit @SqlType(Code)
// we also have an explicit @JdbcType(Code)
jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve(
reflectedJtd,
@ -107,8 +143,8 @@ public class InferredBasicValueResolver {
if ( reflectedJtd instanceof EnumJavaTypeDescriptor ) {
return fromEnum(
(EnumJavaTypeDescriptor) reflectedJtd,
explicitJavaTypeAccess.apply( typeConfiguration ),
explicitSqlTypeAccess.apply( typeConfiguration ),
null,
null,
stdIndicators,
typeConfiguration
);
@ -116,8 +152,8 @@ public class InferredBasicValueResolver {
else if ( reflectedJtd instanceof TemporalJavaTypeDescriptor ) {
return fromTemporal(
(TemporalJavaTypeDescriptor) reflectedJtd,
explicitJavaTypeAccess,
explicitSqlTypeAccess,
null,
null,
stdIndicators,
typeConfiguration
);
@ -128,12 +164,11 @@ public class InferredBasicValueResolver {
final BasicType registeredType = typeConfiguration.getBasicTypeRegistry().getRegisteredType( reflectedJtd.getJavaType() );
if ( registeredType != null ) {
// reuse the "legacy type"
legacyType = resolveSqlTypeIndicators( stdIndicators, registeredType );
legacyType = resolveSqlTypeIndicators( stdIndicators, registeredType, reflectedJtd );
jdbcMapping = legacyType;
}
else if ( reflectedJtd instanceof SerializableTypeDescriptor ) {
legacyType = new SerializableType<>( reflectedJtd.getJavaTypeClass() );
else if ( reflectedJtd instanceof SerializableTypeDescriptor || reflectedJtd.getJavaType() instanceof Serializable ) {
legacyType = new SerializableType<>( reflectedJtd );
jdbcMapping = legacyType;
}
else {
@ -154,7 +189,7 @@ public class InferredBasicValueResolver {
explicitJdbcType
);
jdbcMapping = resolveSqlTypeIndicators( stdIndicators, resolved );
jdbcMapping = resolveSqlTypeIndicators( stdIndicators, resolved, recommendedJtd );
legacyType = jdbcMapping;
}
else {
@ -193,10 +228,11 @@ public class InferredBasicValueResolver {
@SuppressWarnings("rawtypes")
public static BasicType<?> resolveSqlTypeIndicators(
JdbcTypeDescriptorIndicators stdIndicators,
BasicType<?> resolved) {
if ( resolved instanceof SqlTypeDescriptorIndicatorCapable ) {
final SqlTypeDescriptorIndicatorCapable indicatorCapable = (SqlTypeDescriptorIndicatorCapable) resolved;
final BasicType indicatedType = indicatorCapable.resolveIndicatedType( stdIndicators );
BasicType<?> resolved,
JavaTypeDescriptor<?> domainJtd) {
if ( resolved instanceof AdjustableBasicType ) {
final AdjustableBasicType indicatorCapable = (AdjustableBasicType) resolved;
final BasicType indicatedType = indicatorCapable.resolveIndicatedType( stdIndicators, domainJtd );
return indicatedType != null ? indicatedType : resolved;
}
else {
@ -322,28 +358,12 @@ public class InferredBasicValueResolver {
@SuppressWarnings({"rawtypes", "unchecked"})
public static InferredBasicValueResolution fromTemporal(
TemporalJavaTypeDescriptor reflectedJtd,
Function<TypeConfiguration, BasicJavaDescriptor> explicitJavaTypeAccess,
Function<TypeConfiguration, JdbcTypeDescriptor> explicitSqlTypeAccess,
BasicJavaDescriptor explicitJavaType,
JdbcTypeDescriptor explicitJdbcType,
JdbcTypeDescriptorIndicators stdIndicators,
TypeConfiguration typeConfiguration) {
final TemporalType requestedTemporalPrecision = stdIndicators.getTemporalPrecision();
final JavaTypeDescriptor explicitJavaType;
if ( explicitJavaTypeAccess != null ) {
explicitJavaType = explicitJavaTypeAccess.apply( typeConfiguration );
}
else {
explicitJavaType = null;
}
final JdbcTypeDescriptor explicitJdbcType;
if ( explicitSqlTypeAccess != null ) {
explicitJdbcType = explicitSqlTypeAccess.apply( typeConfiguration );
}
else {
explicitJdbcType = null;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Case #1 - @JavaType

View File

@ -40,7 +40,10 @@ import org.hibernate.engine.config.spi.StandardConverters;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.type.BasicType;
import org.hibernate.type.BasicTypeRegistry;
import org.hibernate.type.CustomType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypedExpressable;
import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.usertype.UserType;
@ -355,16 +358,33 @@ public class MetadataBuildingProcess {
@Override
public void contributeType(org.hibernate.type.BasicType type) {
getBasicTypeRegistry().register( type );
final JavaTypeDescriptor<?> jtd;
if ( type instanceof CustomType ) {
final CustomType customType = (CustomType) type;
jtd = customType.getJavaTypeDescriptor();
}
else {
jtd = type.getJavaTypeDescriptor();
}
conditionallyRegisterJtd( jtd );
}
private void conditionallyRegisterJtd(JavaTypeDescriptor jtd) {
final JavaTypeDescriptorRegistry jtdRegistry = getTypeConfiguration().getJavaTypeDescriptorRegistry();
jtdRegistry.resolveDescriptor( jtd.getJavaTypeClass(), () -> jtd );
}
@Override
public void contributeType(BasicType type, String... keys) {
getBasicTypeRegistry().register( type, keys );
conditionallyRegisterJtd( type.getJavaTypeDescriptor() );
}
@Override
public void contributeType(UserType type, String[] keys) {
getBasicTypeRegistry().register( type, keys );
contributeType( new CustomType( type, keys, getTypeConfiguration() ) );
}
@Override
@ -383,7 +403,7 @@ public class MetadataBuildingProcess {
}
final BasicTypeRegistry getBasicTypeRegistry() {
return bootstrapContext.getTypeConfiguration().getBasicTypeRegistry();
return getTypeConfiguration().getBasicTypeRegistry();
}
};

View File

@ -26,6 +26,8 @@ import org.hibernate.MappingException;
import org.hibernate.annotations.CollectionId;
import org.hibernate.annotations.Immutable;
import org.hibernate.annotations.JavaType;
import org.hibernate.annotations.JdbcType;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.annotations.MapKeyJavaType;
import org.hibernate.annotations.MapKeyJdbcType;
import org.hibernate.annotations.MapKeyJdbcTypeCode;
@ -33,8 +35,6 @@ import org.hibernate.annotations.MapKeyType;
import org.hibernate.annotations.Mutability;
import org.hibernate.annotations.Nationalized;
import org.hibernate.annotations.Parameter;
import org.hibernate.annotations.JdbcType;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
@ -49,6 +49,7 @@ import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.cfg.PkDrivenByDefaultMapsIdSecondPass;
import org.hibernate.cfg.SetBasicValueTypeSecondPass;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.NationalizationSupport;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
@ -256,7 +257,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
isLob = modelXProperty.isAnnotationPresent( Lob.class );
}
if ( getDialect().supportsNationalizedTypes() ) {
if ( getDialect().getNationalizationSupport() == NationalizationSupport.EXPLICIT ) {
isNationalized = modelXProperty.isAnnotationPresent( Nationalized.class )
|| buildingContext.getBuildingOptions().useNationalizedCharacterData();
}

View File

@ -234,8 +234,9 @@ public class CockroachDialect extends Dialect {
}
@Override
public boolean supportsNationalizedTypes() {
return false;
public NationalizationSupport getNationalizationSupport() {
// TEXT / STRING inherently support nationalized data
return NationalizationSupport.IMPLICIT;
}
@Override

View File

@ -74,6 +74,7 @@ public class DerbyDialect extends Dialect {
// KNOWN LIMITATIONS:
// no support for nationalized data (nchar, nvarchar, nclob)
// * limited set of fields for extract()
// (no 'day of xxxx', nor 'week of xxxx')
// * no support for format()
@ -160,6 +161,11 @@ public class DerbyDialect extends Dialect {
return version;
}
@Override
public NationalizationSupport getNationalizationSupport() {
return NationalizationSupport.IMPLICIT;
}
@Override
public int getFloatPrecision() {
return 23;

View File

@ -82,6 +82,10 @@ import org.hibernate.type.Type;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.ClobTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.LongNVarcharTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.NCharTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.NClobTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.NVarcharTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import javax.persistence.TemporalType;
@ -958,7 +962,15 @@ public abstract class Dialect implements ConversionContext {
* @param serviceRegistry The service registry
*/
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
// by default, nothing to do
// by default, not much to do...
final NationalizationSupport nationalizationSupport = getNationalizationSupport();
if ( nationalizationSupport == NationalizationSupport.EXPLICIT ) {
typeContributions.contributeJdbcTypeDescriptor( NCharTypeDescriptor.INSTANCE );
typeContributions.contributeJdbcTypeDescriptor( NVarcharTypeDescriptor.INSTANCE );
typeContributions.contributeJdbcTypeDescriptor( LongNVarcharTypeDescriptor.INSTANCE );
typeContributions.contributeJdbcTypeDescriptor( NClobTypeDescriptor.DEFAULT );
}
}
// public static interface Initializable {
@ -3441,9 +3453,18 @@ public abstract class Dialect implements ConversionContext {
* Does this dialect supports Nationalized Types
*
* @return boolean
*
* @deprecated (since 6.0) Prefer {@link #getNationalizationSupport()} which gives a little
* better insight into what is supported. This is interpreted as true if the supported
* strategy is {@link NationalizationSupport#EXPLICIT}
*/
public boolean supportsNationalizedTypes() {
return true;
@Deprecated
public final boolean supportsNationalizedTypes() {
return getNationalizationSupport() == NationalizationSupport.EXPLICIT;
}
public NationalizationSupport getNationalizationSupport() {
return NationalizationSupport.EXPLICIT;
}
/**

View File

@ -0,0 +1,69 @@
/*
* 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.dialect;
import java.sql.Types;
/**
* Indicates how (if) the underlying database supports the use of nationalized data
*/
public enum NationalizationSupport {
/**
* The database's CHAR, VARCHAR, LONGVARCHAR and CLOB types
* inherently handle nationalized data. Generally speaking
* this means the database will not have dedicated nationalized
* data types (NCHAR, ...)
*/
IMPLICIT( Types.CHAR, Types.VARCHAR, Types.LONGVARCHAR, Types.CLOB ),
/**
* The database does define/support distinct nationalized
* data types (NCHAR, ...).
*/
EXPLICIT( Types.NCHAR, Types.NVARCHAR, Types.LONGNVARCHAR, Types.NCLOB ),
/**
* The database does not define/support distinct nationalized
* data types (NCHAR, ...) and its corresponding base data
* types (CHAR, ...) do not support nationalized data
*/
UNSUPPORTED;
private final int charVariantCode;
private final int varcharVariantCode;
private final int longVarcharVariantCode;
private final int clobVariantCode;
NationalizationSupport() {
this( -1, -1, -1, -1 );
}
NationalizationSupport(
int charVariantCode,
int varcharVariantCode,
int longVarcharVariantCode,
int clobVariantCode) {
this.charVariantCode = charVariantCode;
this.varcharVariantCode = varcharVariantCode;
this.longVarcharVariantCode = longVarcharVariantCode;
this.clobVariantCode = clobVariantCode;
}
public int getCharVariantCode() {
return charVariantCode;
}
public int getVarcharVariantCode() {
return varcharVariantCode;
}
public int getLongVarcharVariantCode() {
return longVarcharVariantCode;
}
public int getClobVariantCode() {
return clobVariantCode;
}
}

View File

@ -658,8 +658,8 @@ public class PostgreSQLDialect extends Dialect {
}
@Override
public boolean supportsNationalizedTypes() {
return false;
public NationalizationSupport getNationalizationSupport() {
return NationalizationSupport.IMPLICIT;
}
@Override

View File

@ -14,7 +14,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Objects;
import java.util.Properties;
import javax.persistence.AttributeConverter;
@ -52,9 +51,9 @@ import org.hibernate.type.descriptor.JdbcTypeNameMapper;
import org.hibernate.type.descriptor.converter.AttributeConverterJdbcTypeDescriptorAdapter;
import org.hibernate.type.descriptor.converter.AttributeConverterTypeAdapter;
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.LobTypeMappings;
import org.hibernate.type.descriptor.jdbc.NationalizedTypeMappings;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.usertype.DynamicParameterizedType;

View File

@ -13,10 +13,14 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.named.ResultMementoBasic;
import org.hibernate.query.results.ResultBuilderBasicValued;
import org.hibernate.query.results.complete.CompleteResultBuilderBasicValuedStandard;
import org.hibernate.resource.beans.spi.ManagedBean;
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
import org.hibernate.type.BasicType;
import org.hibernate.type.CustomType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry;
import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.usertype.UserType;
/**
* Implementation of ResultMappingMemento for scalar (basic) results.
@ -60,6 +64,8 @@ public class ResultMementoBasicStandard implements ResultMementoBasic {
ResultSetMappingResolutionContext context) {
this.explicitColumnName = definition.name();
BasicType resolvedBasicType = null;
final Class<?> definedType = definition.type();
if ( void.class == definedType ) {
explicitJavaTypeDescriptor = null;
@ -67,11 +73,35 @@ public class ResultMementoBasicStandard implements ResultMementoBasic {
else {
final SessionFactoryImplementor sessionFactory = context.getSessionFactory();
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
final JavaTypeDescriptorRegistry jtdRegistry = typeConfiguration.getJavaTypeDescriptorRegistry();
this.explicitJavaTypeDescriptor = jtdRegistry.getDescriptor( definition.type() );
// first see if this is a registered BasicType...
final BasicType<Object> registeredBasicType = typeConfiguration.getBasicTypeRegistry()
.getRegisteredType( definition.type().getName() );
if ( registeredBasicType != null ) {
this.explicitJavaTypeDescriptor = registeredBasicType.getJavaTypeDescriptor();
}
else {
final JavaTypeDescriptorRegistry jtdRegistry = typeConfiguration.getJavaTypeDescriptorRegistry();
final JavaTypeDescriptor<Object> registeredJtd = jtdRegistry.getDescriptor( definition.type() );
final ManagedBeanRegistry beanRegistry = sessionFactory.getServiceRegistry().getService( ManagedBeanRegistry.class );
if ( BasicType.class.isAssignableFrom( registeredJtd.getJavaTypeClass() ) ) {
final ManagedBean<BasicType<?>> typeBean = (ManagedBean) beanRegistry.getBean( registeredJtd.getJavaTypeClass() );
resolvedBasicType = typeBean.getBeanInstance();
this.explicitJavaTypeDescriptor = resolvedBasicType.getJavaTypeDescriptor();
}
else if ( UserType.class.isAssignableFrom( registeredJtd.getJavaTypeClass() ) ) {
final ManagedBean<UserType<?>> userTypeBean = (ManagedBean) beanRegistry.getBean( registeredJtd.getJavaTypeClass() );
// todo (6.0) : is this the best approach? or should we keep a Class<? extends UserType> -> CustomType mapping somewhere?
resolvedBasicType = new CustomType( userTypeBean.getBeanInstance(), sessionFactory.getTypeConfiguration() );
this.explicitJavaTypeDescriptor = resolvedBasicType.getJavaTypeDescriptor();
}
else {
this.explicitJavaTypeDescriptor = jtdRegistry.getDescriptor( definition.type() );
}
}
}
explicitType = null;
explicitType = resolvedBasicType;
}
public ResultMementoBasicStandard(

View File

@ -41,6 +41,11 @@ public class CompleteResultBuilderBasicValuedStandard implements CompleteResultB
String explicitColumnName,
BasicValuedMapping explicitType,
JavaTypeDescriptor<?> explicitJavaTypeDescriptor) {
assert explicitType == null || explicitType.getJdbcMapping()
.getJavaTypeDescriptor()
.getJavaTypeClass()
.isAssignableFrom( explicitJavaTypeDescriptor.getJavaTypeClass() );
this.explicitColumnName = explicitColumnName;
this.explicitType = explicitType;
this.explicitJavaTypeDescriptor = explicitJavaTypeDescriptor;
@ -63,6 +68,35 @@ public class CompleteResultBuilderBasicValuedStandard implements CompleteResultB
columnName = jdbcResultsMetadata.resolveColumnName( resultPosition + 1 );
}
// final int jdbcPosition;
// if ( explicitColumnName != null ) {
// jdbcPosition = jdbcResultsMetadata.resolveColumnPosition( explicitColumnName );
// }
// else {
// jdbcPosition = resultPosition + 1;
// }
//
// final BasicValuedMapping basicType;
// if ( explicitType != null ) {
// basicType = explicitType;
// }
// else {
// basicType = jdbcResultsMetadata.resolveType( jdbcPosition, explicitJavaTypeDescriptor );
// }
//
// final SqlSelection sqlSelection = creationStateImpl.resolveSqlSelection(
// creationStateImpl.resolveSqlExpression(
// columnName,
// processingState -> {
// final int valuesArrayPosition = ResultsHelper.jdbcPositionToValuesArrayPosition( jdbcPosition );
// return new SqlSelectionImpl( valuesArrayPosition, basicType );
// }
// ),
// basicType.getExpressableJavaTypeDescriptor(),
// sessionFactory.getTypeConfiguration()
// );
final SqlSelection sqlSelection = creationStateImpl.resolveSqlSelection(
creationStateImpl.resolveSqlExpression(
columnName,
@ -74,7 +108,6 @@ public class CompleteResultBuilderBasicValuedStandard implements CompleteResultB
else {
jdbcPosition = resultPosition + 1;
}
final int valuesArrayPosition = ResultsHelper.jdbcPositionToValuesArrayPosition( jdbcPosition );
final BasicValuedMapping basicType;
if ( explicitType != null ) {
@ -83,6 +116,8 @@ public class CompleteResultBuilderBasicValuedStandard implements CompleteResultB
else {
basicType = jdbcResultsMetadata.resolveType( jdbcPosition, explicitJavaTypeDescriptor );
}
final int valuesArrayPosition = ResultsHelper.jdbcPositionToValuesArrayPosition( jdbcPosition );
return new SqlSelectionImpl( valuesArrayPosition, basicType );
}
),

View File

@ -2351,7 +2351,11 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
getFromClauseAccess()::findTableGroup
);
if ( localExpressable instanceof BasicType<?> ) {
expressable = InferredBasicValueResolver.resolveSqlTypeIndicators( this, (BasicType<?>) localExpressable );
expressable = InferredBasicValueResolver.resolveSqlTypeIndicators(
this,
(BasicType<?>) localExpressable,
literal.getJavaTypeDescriptor()
);
}
else {
expressable = localExpressable;
@ -2761,7 +2765,11 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
public Object visitCastTarget(SqmCastTarget target) {
BasicValuedMapping targetType = (BasicValuedMapping) target.getType();
if ( targetType instanceof BasicType<?> ) {
targetType = InferredBasicValueResolver.resolveSqlTypeIndicators( this, (BasicType<?>) targetType );
targetType = InferredBasicValueResolver.resolveSqlTypeIndicators(
this,
(BasicType<?>) targetType,
target.getNodeJavaTypeDescriptor()
);
}
return new CastTarget(
targetType.getJdbcMapping(),

View File

@ -72,12 +72,12 @@ public abstract class AbstractStandardBasicType<T>
}
@Override
public ValueExtractor getJdbcValueExtractor() {
public ValueExtractor<T> getJdbcValueExtractor() {
return jdbcValueExtractor;
}
@Override
public ValueBinder getJdbcValueBinder() {
public ValueBinder<T> getJdbcValueBinder() {
return jdbcValueBinder;
}

View File

@ -6,14 +6,17 @@
*/
package org.hibernate.type;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
/**
* @author Steve Ebersole
* Extension contract for BasicType implementations that understand how to
* adjust themselves relative to where/how they are used (e.g. accounting
* for LOB, nationalized, primitive/wrapper, etc).
*/
public interface SqlTypeDescriptorIndicatorCapable<J> extends BasicType<J> {
public interface AdjustableBasicType<J> extends BasicType<J> {
/**
* For Types whose resolution can be affected by SqlTypeDescriptorIndicators
* Perform the adjustment
*/
<X> BasicType<X> resolveIndicatedType(JdbcTypeDescriptorIndicators indicators);
<X> BasicType<X> resolveIndicatedType(JdbcTypeDescriptorIndicators indicators, JavaTypeDescriptor<X> domainJtd);
}

View File

@ -48,6 +48,8 @@ public interface BasicType<T> extends Type, BasicDomainType<T>, MappingType, Bas
return getJavaTypeDescriptor();
}
@Override
default int forEachJdbcType(IndexedConsumer<JdbcMapping> action) {
action.accept( 0, this );

View File

@ -50,6 +50,11 @@ public class BasicTypeRegistry implements Serializable {
}
public <J> BasicType<J> getRegisteredType(java.lang.reflect.Type javaType) {
if ( javaType instanceof Class ) {
// using `javaType.getTypeName()` causes problems with arrays
//noinspection unchecked
return getRegisteredType( (Class<J>) javaType );
}
return getRegisteredType( javaType.getTypeName() );
}

View File

@ -6,11 +6,17 @@
*/
package org.hibernate.type;
import java.sql.Types;
import java.util.Comparator;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
import org.hibernate.type.descriptor.jdbc.VarbinaryTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.type.spi.TypeConfiguration;
/**
* A type that maps between a {@link java.sql.Types#VARBINARY VARBINARY} and {@code byte[]}
@ -23,7 +29,7 @@ import org.hibernate.type.descriptor.jdbc.VarbinaryTypeDescriptor;
*/
public class BinaryType
extends AbstractSingleColumnStandardBasicType<byte[]>
implements VersionType<byte[]> {
implements VersionType<byte[]>, AdjustableBasicType<byte[]> {
public static final BinaryType INSTANCE = new BinaryType();
@ -82,4 +88,18 @@ public class BinaryType
public Comparator<byte[]> getComparator() {
return PrimitiveByteArrayTypeDescriptor.INSTANCE.getComparator();
}
@Override
@SuppressWarnings("unchecked")
public <X> BasicType<X> resolveIndicatedType(JdbcTypeDescriptorIndicators indicators, JavaTypeDescriptor<X> domainJtd) {
if ( ! indicators.isLob() ) {
return (BasicType<X>) this;
}
final TypeConfiguration typeConfiguration = indicators.getTypeConfiguration();
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeDescriptorRegistry();
final JdbcTypeDescriptor jdbcType = jdbcTypeRegistry.getDescriptor( Types.BLOB );
return typeConfiguration.getBasicTypeRegistry().resolve( domainJtd, jdbcType );
}
}

View File

@ -9,8 +9,10 @@ package org.hibernate.type;
import java.io.Serializable;
import java.sql.Types;
import org.hibernate.Incubating;
import org.hibernate.dialect.Dialect;
import org.hibernate.type.descriptor.java.BooleanTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
@ -22,7 +24,7 @@ import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
*/
public class BooleanType
extends AbstractSingleColumnStandardBasicType<Boolean>
implements PrimitiveType<Boolean>, DiscriminatorType<Boolean>, SqlTypeDescriptorIndicatorCapable<Boolean> {
implements PrimitiveType<Boolean>, DiscriminatorType<Boolean>, AdjustableBasicType<Boolean> {
public static final BooleanType INSTANCE = new BooleanType();
public BooleanType() {
@ -32,6 +34,12 @@ public class BooleanType
protected BooleanType(JdbcTypeDescriptor jdbcTypeDescriptor, BooleanTypeDescriptor javaTypeDescriptor) {
super( jdbcTypeDescriptor, javaTypeDescriptor );
}
@Incubating
public BooleanType(JdbcTypeDescriptor jdbcTypeDescriptor, JavaTypeDescriptor<Boolean> javaTypeDescriptor) {
super( jdbcTypeDescriptor, javaTypeDescriptor );
}
@Override
public String getName() {
return "boolean";
@ -60,7 +68,9 @@ public class BooleanType
}
@Override
public <X> BasicType<X> resolveIndicatedType(JdbcTypeDescriptorIndicators indicators) {
public <X> BasicType<X> resolveIndicatedType(
JdbcTypeDescriptorIndicators indicators,
JavaTypeDescriptor<X> domainJtd) {
final int preferredSqlTypeCodeForBoolean = indicators.getPreferredSqlTypeCodeForBoolean();
final JdbcTypeDescriptor jdbcTypeDescriptor;
// We treat BIT like BOOLEAN because it uses the same JDBC access methods

View File

@ -7,10 +7,13 @@
package org.hibernate.type;
import java.sql.Types;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.PrimitiveCharacterArrayTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
import org.hibernate.type.descriptor.jdbc.VarcharTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.type.spi.TypeConfiguration;
/**
* A type that maps between {@link java.sql.Types#VARCHAR VARCHAR} and {@code char[]}
@ -20,7 +23,7 @@ import org.hibernate.type.descriptor.jdbc.VarcharTypeDescriptor;
*/
public class CharArrayType
extends AbstractSingleColumnStandardBasicType<char[]>
implements SqlTypeDescriptorIndicatorCapable<char[]> {
implements AdjustableBasicType<char[]> {
public static final CharArrayType INSTANCE = new CharArrayType();
public CharArrayType() {
@ -37,22 +40,23 @@ public class CharArrayType
}
@Override
public <X> BasicType<X> resolveIndicatedType(JdbcTypeDescriptorIndicators indicators) {
public <X> BasicType<X> resolveIndicatedType(
JdbcTypeDescriptorIndicators indicators,
JavaTypeDescriptor<X> domainJtd) {
assert domainJtd != null;
final TypeConfiguration typeConfiguration = indicators.getTypeConfiguration();
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeDescriptorRegistry();
final int jdbcTypeCode;
if ( indicators.isLob() ) {
//noinspection unchecked
return (BasicType<X>) ( indicators.isNationalized() ? CharacterArrayNClobType.INSTANCE : CharacterArrayClobType.INSTANCE );
jdbcTypeCode = indicators.isNationalized() ? Types.NCLOB : Types.CLOB;
}
else {
jdbcTypeCode = indicators.isNationalized() ? Types.NVARCHAR : Types.VARCHAR;
}
if ( indicators.isNationalized() ) {
final JdbcTypeDescriptor nvarcharType = indicators.getTypeConfiguration()
.getJdbcTypeDescriptorRegistry()
.getDescriptor( Types.NVARCHAR );
//noinspection unchecked
return (BasicType<X>) indicators.getTypeConfiguration().getBasicTypeRegistry().resolve( getJavaTypeDescriptor(), nvarcharType );
}
//noinspection unchecked
return (BasicType<X>) this;
final JdbcTypeDescriptor jdbcType = jdbcTypeRegistry.getDescriptor( jdbcTypeCode );
return typeConfiguration.getBasicTypeRegistry().resolve( domainJtd, jdbcType );
}
}

View File

@ -6,9 +6,15 @@
*/
package org.hibernate.type;
import java.sql.Types;
import org.hibernate.type.descriptor.java.CharacterArrayTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.ClobTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.type.spi.TypeConfiguration;
/**
* A type that maps between {@link java.sql.Types#CLOB CLOB} and {@link Character Character[]}
@ -20,7 +26,7 @@ import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
*/
public class CharacterArrayClobType
extends AbstractSingleColumnStandardBasicType<Character[]>
implements SqlTypeDescriptorIndicatorCapable<Character[]> {
implements AdjustableBasicType<Character[]> {
public static final CharacterArrayClobType INSTANCE = new CharacterArrayClobType();
public CharacterArrayClobType() {
@ -33,8 +39,23 @@ public class CharacterArrayClobType
}
@Override
public <X> BasicType<X> resolveIndicatedType(JdbcTypeDescriptorIndicators indicators) {
//noinspection unchecked
public <X> BasicType<X> resolveIndicatedType(
JdbcTypeDescriptorIndicators indicators,
JavaTypeDescriptor<X> domainJtd) {
if ( domainJtd != null && domainJtd.getJavaTypeClass() == char[].class ) {
// domainJtd is a `char[]` instead of a `Character[]`....
final TypeConfiguration typeConfiguration = indicators.getTypeConfiguration();
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeDescriptorRegistry();
final JdbcTypeDescriptor jdbcType = indicators.isNationalized()
? jdbcTypeRegistry.getDescriptor( Types.NCLOB )
: jdbcTypeRegistry.getDescriptor( Types.CLOB );
return typeConfiguration.getBasicTypeRegistry().resolve(
typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( domainJtd.getJavaType() ),
jdbcType
);
}
return (BasicType<X>) ( indicators.isNationalized() ? CharacterArrayNClobType.INSTANCE : this );
}
}

View File

@ -6,8 +6,15 @@
*/
package org.hibernate.type;
import java.sql.Types;
import org.hibernate.type.descriptor.java.CharacterArrayTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
import org.hibernate.type.descriptor.jdbc.NClobTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.type.spi.TypeConfiguration;
/**
* A type that maps between {@link java.sql.Types#NCLOB NCLOB} and {@link Character Character[]}
@ -17,7 +24,9 @@ import org.hibernate.type.descriptor.jdbc.NClobTypeDescriptor;
* @author Emmanuel Bernard
* @author Steve Ebersole
*/
public class CharacterArrayNClobType extends AbstractSingleColumnStandardBasicType<Character[]> {
public class CharacterArrayNClobType
extends AbstractSingleColumnStandardBasicType<Character[]>
implements AdjustableBasicType<Character[]> {
public static final CharacterArrayNClobType INSTANCE = new CharacterArrayNClobType();
public CharacterArrayNClobType() {
@ -29,4 +38,23 @@ public class CharacterArrayNClobType extends AbstractSingleColumnStandardBasicTy
return null;
}
@Override
public <X> BasicType<X> resolveIndicatedType(
JdbcTypeDescriptorIndicators indicators,
JavaTypeDescriptor<X> domainJtd) {
if ( domainJtd != null && domainJtd.getJavaTypeClass() == char[].class ) {
// domainJtd is a `char[]` instead of a `Character[]`....
final TypeConfiguration typeConfiguration = indicators.getTypeConfiguration();
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeDescriptorRegistry();
final JdbcTypeDescriptor jdbcType = jdbcTypeRegistry.getDescriptor( Types.NCLOB );
return typeConfiguration.getBasicTypeRegistry().resolve(
typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( domainJtd.getJavaType() ),
jdbcType
);
}
//noinspection unchecked
return (BasicType<X>) this;
}
}

View File

@ -8,9 +8,11 @@ package org.hibernate.type;
import java.sql.Types;
import org.hibernate.type.descriptor.java.CharacterArrayTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
import org.hibernate.type.descriptor.jdbc.VarcharTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.type.spi.TypeConfiguration;
/**
@ -21,7 +23,7 @@ import org.hibernate.type.spi.TypeConfiguration;
*/
public class CharacterArrayType
extends AbstractSingleColumnStandardBasicType<Character[]>
implements SqlTypeDescriptorIndicatorCapable<Character[]> {
implements AdjustableBasicType<Character[]> {
public static final CharacterArrayType INSTANCE = new CharacterArrayType();
public CharacterArrayType() {
@ -38,26 +40,36 @@ public class CharacterArrayType
}
@Override
public <X> BasicType<X> resolveIndicatedType(JdbcTypeDescriptorIndicators indicators) {
if ( indicators.isNationalized() ) {
final TypeConfiguration typeConfiguration = indicators.getTypeConfiguration();
if ( indicators.isLob() ) {
//noinspection unchecked
return (BasicType<X>) CharacterArrayNClobType.INSTANCE;
}
else {
final JdbcTypeDescriptor nvarcharType = typeConfiguration.getJdbcTypeDescriptorRegistry().getDescriptor( Types.NVARCHAR );
//noinspection unchecked
return (BasicType<X>) typeConfiguration.getBasicTypeRegistry().resolve( getJavaTypeDescriptor(), nvarcharType );
}
}
public <X> BasicType<X> resolveIndicatedType(
JdbcTypeDescriptorIndicators indicators,
JavaTypeDescriptor<X> domainJtd) {
final TypeConfiguration typeConfiguration = indicators.getTypeConfiguration();
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeDescriptorRegistry();
final int jdbcTypeCode;
if ( indicators.isLob() ) {
//noinspection unchecked
return (BasicType<X>) CharacterArrayClobType.INSTANCE;
jdbcTypeCode = indicators.isNationalized() ? Types.NCLOB : Types.CLOB;
}
else {
jdbcTypeCode = indicators.isNationalized() ? Types.NVARCHAR : Types.VARCHAR;
}
//noinspection unchecked
return (BasicType<X>) this;
final JdbcTypeDescriptor indicatedJdbcType = jdbcTypeRegistry.getDescriptor( jdbcTypeCode );
if ( domainJtd != null && domainJtd.getJavaTypeClass() == Character[].class ) {
return typeConfiguration.getBasicTypeRegistry().resolve(
typeConfiguration.getJavaTypeDescriptorRegistry().resolveDescriptor( domainJtd.getJavaType() ),
indicatedJdbcType
);
}
if ( getJdbcTypeDescriptor() == indicatedJdbcType ) {
return (BasicType<X>) this;
}
return (BasicType<X>) typeConfiguration.getBasicTypeRegistry().resolve(
getJavaTypeDescriptor(),
indicatedJdbcType
);
}
}

View File

@ -7,11 +7,16 @@
package org.hibernate.type;
import java.io.Serializable;
import java.sql.Types;
import org.hibernate.dialect.Dialect;
import org.hibernate.type.descriptor.java.CharacterTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.CharTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.type.spi.TypeConfiguration;
/**
* A type that maps between {@link java.sql.Types#CHAR CHAR(1)} and {@link Character}
@ -21,7 +26,7 @@ import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
*/
public class CharacterType
extends AbstractSingleColumnStandardBasicType<Character>
implements PrimitiveType<Character>, DiscriminatorType<Character>, SqlTypeDescriptorIndicatorCapable<Character> {
implements PrimitiveType<Character>, DiscriminatorType<Character>, AdjustableBasicType<Character> {
public static final CharacterType INSTANCE = new CharacterType();
@ -55,7 +60,15 @@ public class CharacterType
}
@Override
public <X> BasicType<X> resolveIndicatedType(JdbcTypeDescriptorIndicators indicators) {
return (BasicType<X>) ( indicators.isNationalized() ? CharacterNCharType.INSTANCE : this );
public <X> BasicType<X> resolveIndicatedType(
JdbcTypeDescriptorIndicators indicators,
JavaTypeDescriptor<X> domainJtd) {
final TypeConfiguration typeConfiguration = indicators.getTypeConfiguration();
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeDescriptorRegistry();
final JdbcTypeDescriptor jdbcType = indicators.isNationalized()
? jdbcTypeRegistry.getDescriptor( Types.NCHAR )
: jdbcTypeRegistry.getDescriptor( Types.CHAR );
return typeConfiguration.getBasicTypeRegistry().resolve( domainJtd, jdbcType );
}
}

View File

@ -7,10 +7,14 @@
package org.hibernate.type;
import java.sql.Clob;
import java.sql.Types;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.type.descriptor.java.ClobTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.type.spi.TypeConfiguration;
/**
* A type that maps between {@link java.sql.Types#CLOB CLOB} and {@link Clob}
@ -18,7 +22,7 @@ import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
* @author Gavin King
* @author Steve Ebersole
*/
public class ClobType extends AbstractSingleColumnStandardBasicType<Clob> implements SqlTypeDescriptorIndicatorCapable<Clob> {
public class ClobType extends AbstractSingleColumnStandardBasicType<Clob> implements AdjustableBasicType<Clob> {
public static final ClobType INSTANCE = new ClobType();
public ClobType() {
@ -40,16 +44,21 @@ public class ClobType extends AbstractSingleColumnStandardBasicType<Clob> implem
return session.getJdbcServices().getJdbcEnvironment().getDialect().getLobMergeStrategy().mergeClob( original, target, session );
}
@SuppressWarnings({"rawtypes", "unchecked"})
@Override
public BasicType resolveIndicatedType(JdbcTypeDescriptorIndicators indicators) {
// todo (6.0) : Support a "wrapped clob"? This would be a (N)VARCHAR column we handle as a Clob in-memory
// - might be especially interesting for streaming based (N)VARCHAR reading
if ( indicators.isNationalized() ) {
return NClobType.INSTANCE;
@SuppressWarnings( "unchecked" )
public <X> BasicType<X> resolveIndicatedType(
JdbcTypeDescriptorIndicators indicators,
JavaTypeDescriptor<X> domainJtd) {
if ( ! indicators.isNationalized() ) {
return (BasicType<X>) this;
}
return this;
final TypeConfiguration typeConfiguration = indicators.getTypeConfiguration();
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeDescriptorRegistry();
return typeConfiguration.getBasicTypeRegistry().resolve(
domainJtd,
jdbcTypeRegistry.getDescriptor( Types.NCLOB )
);
}
}

View File

@ -25,12 +25,14 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypedExpressable;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.internal.UserTypeJavaTypeWrapper;
import org.hibernate.type.internal.UserTypeSqlTypeAdapter;
import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.usertype.EnhancedUserType;
import org.hibernate.usertype.LoggableUserType;
import org.hibernate.usertype.Sized;
import org.hibernate.usertype.UserType;
import org.hibernate.usertype.UserVersionType;
@ -51,23 +53,22 @@ import org.hibernate.usertype.UserVersionType;
*/
public class CustomType
extends AbstractType
implements BasicType, IdentifierType, DiscriminatorType, VersionType, StringRepresentableType, ProcedureParameterNamedBinder, ProcedureParameterExtractionAware, ValueBinder {
implements BasicType, IdentifierType, DiscriminatorType, VersionType, StringRepresentableType, ProcedureParameterNamedBinder, ProcedureParameterExtractionAware {
private final UserType userType;
private final UserType<Object> userType;
private final String[] registrationKeys;
private final String name;
private final JavaTypeDescriptor mappedJavaTypeDescriptor;
private final BasicJavaDescriptor<Object> mappedJavaTypeDescriptor;
private final JdbcTypeDescriptor jdbcTypeDescriptor;
private final ValueExtractor valueExtractor;
private final ValueExtractor<Object> valueExtractor;
private final ValueBinder<Object> valueBinder;
private final Size dictatedSize;
private final Size defaultSize;
private final boolean customLogging;
public CustomType(UserType userType, TypeConfiguration typeConfiguration) throws MappingException {
this( userType, ArrayHelper.EMPTY_STRING_ARRAY, typeConfiguration );
}
@ -76,9 +77,23 @@ public class CustomType
this.userType = userType;
this.name = userType.getClass().getName();
//noinspection unchecked
this.mappedJavaTypeDescriptor = typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( userType.returnedClass() );
this.jdbcTypeDescriptor = typeConfiguration.getJdbcTypeDescriptorRegistry().getDescriptor( userType.sqlTypes()[0] );
if ( userType instanceof BasicJavaDescriptor ) {
//noinspection rawtypes
this.mappedJavaTypeDescriptor = ( (BasicJavaDescriptor) userType );
}
else if ( userType instanceof JavaTypedExpressable ) {
//noinspection rawtypes
this.mappedJavaTypeDescriptor = (BasicJavaDescriptor) ( (JavaTypedExpressable) userType ).getExpressableJavaTypeDescriptor();
}
else {
this.mappedJavaTypeDescriptor = new UserTypeJavaTypeWrapper<>( userType );
}
// create a JdbcTypeDescriptor adapter that uses the UserType binde/extract handling
this.jdbcTypeDescriptor = new UserTypeSqlTypeAdapter<>( userType, mappedJavaTypeDescriptor );
this.valueExtractor = jdbcTypeDescriptor.getExtractor( mappedJavaTypeDescriptor );
this.valueBinder = jdbcTypeDescriptor.getBinder( mappedJavaTypeDescriptor );
if ( userType instanceof Sized ) {
final Sized sized = (Sized) userType;
@ -90,35 +105,11 @@ public class CustomType
this.defaultSize = null;
}
if ( userType instanceof ValueExtractor ) {
this.valueExtractor = (ValueExtractor) userType;
}
else {
this.valueExtractor = jdbcTypeDescriptor.getExtractor( mappedJavaTypeDescriptor );
}
this.customLogging = userType instanceof LoggableUserType;
this.registrationKeys = registrationKeys;
}
@Override
public ValueBinder<?> getJdbcValueBinder() {
return this;
}
@Override
public void bind(PreparedStatement st, Object value, int index, WrapperOptions options) throws SQLException {
userType.nullSafeSet( st, value, index, options.getSession() );
}
@Override
public void bind(CallableStatement st, Object value, String name, WrapperOptions options) throws SQLException {
if ( userType instanceof ProcedureParameterNamedBinder ) {
final ProcedureParameterNamedBinder namedParamSupport = (ProcedureParameterNamedBinder) userType;
if ( namedParamSupport.canDoSetting() ) {
namedParamSupport.nullSafeSet( st, value, name, options.getSession() );
}
}
public UserType getUserType() {
return userType;
}
@Override
@ -126,8 +117,9 @@ public class CustomType
return valueExtractor;
}
public UserType getUserType() {
return userType;
@Override
public ValueBinder<?> getJdbcValueBinder() {
return valueBinder;
}
@Override
@ -181,7 +173,7 @@ public class CustomType
String[] names,
SharedSessionContractImplementor session,
Object owner) throws SQLException {
return getUserType().nullSafeGet( rs, names, session, owner);
throw new UnsupportedOperationException( "Reading from ResultSet by name is no longer supported" );
}
@Override
@ -190,7 +182,7 @@ public class CustomType
String columnName,
SharedSessionContractImplementor session,
Object owner) throws SQLException {
return nullSafeGet(rs, new String[] { columnName }, session, owner);
throw new UnsupportedOperationException( "Reading from ResultSet by name is no longer supported" );
}
@Override
@ -285,14 +277,10 @@ public class CustomType
}
@Override
public String toLoggableString(Object value, SessionFactoryImplementor factory)
throws HibernateException {
public String toLoggableString(Object value, SessionFactoryImplementor factory) {
if ( value == null ) {
return "null";
}
else if ( customLogging ) {
return ( ( LoggableUserType ) getUserType() ).toLoggableString( value, factory );
}
else {
return toXMLString( value, factory );
}

View File

@ -17,7 +17,9 @@ import org.hibernate.type.descriptor.java.DoubleTypeDescriptor;
* @author Gavin King
* @author Steve Ebersole
*/
public class DoubleType extends AbstractSingleColumnStandardBasicType<Double> implements PrimitiveType<Double> {
public class DoubleType
extends AbstractSingleColumnStandardBasicType<Double>
implements PrimitiveType<Double> {
public static final DoubleType INSTANCE = new DoubleType();
public static final Double ZERO = 0.0;

View File

@ -19,7 +19,6 @@ import javax.persistence.MapKeyEnumerated;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.annotations.Nationalized;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
@ -29,6 +28,8 @@ import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.metamodel.model.convert.internal.NamedEnumValueConverter;
import org.hibernate.metamodel.model.convert.internal.OrdinalEnumValueConverter;
import org.hibernate.metamodel.model.convert.spi.EnumValueConverter;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
import org.hibernate.type.descriptor.java.EnumJavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
@ -78,7 +79,10 @@ public class EnumType<T extends Enum<T>>
private Class<T> enumClass;
private EnumValueConverter<T,?> enumValueConverter;
private EnumValueConverter<T,Object> enumValueConverter;
private JdbcTypeDescriptor jdbcTypeDescriptor;
private ValueExtractor<T> jdbcValueExtractor;
private ValueBinder<T> jdbcValueBinder;
private TypeConfiguration typeConfiguration;
@ -90,8 +94,12 @@ public class EnumType<T extends Enum<T>>
EnumValueConverter enumValueConverter,
TypeConfiguration typeConfiguration) {
this.enumClass = enumClass;
this.enumValueConverter = enumValueConverter;
this.typeConfiguration = typeConfiguration;
this.enumValueConverter = enumValueConverter;
this.jdbcTypeDescriptor = typeConfiguration.getJdbcTypeDescriptorRegistry().getDescriptor( enumValueConverter.getJdbcTypeCode() );
this.jdbcValueExtractor = jdbcTypeDescriptor.getExtractor( enumValueConverter.getRelationalJavaDescriptor() );
this.jdbcValueBinder = jdbcTypeDescriptor.getBinder( enumValueConverter.getRelationalJavaDescriptor() );
}
public EnumValueConverter getEnumValueConverter() {
@ -171,6 +179,9 @@ public class EnumType<T extends Enum<T>>
}
this.enumValueConverter = interpretParameters( parameters );
this.jdbcTypeDescriptor = typeConfiguration.getJdbcTypeDescriptorRegistry().getDescriptor( enumValueConverter.getJdbcTypeCode() );
this.jdbcValueExtractor = (ValueExtractor) jdbcTypeDescriptor.getExtractor( enumValueConverter.getRelationalJavaDescriptor() );
this.jdbcValueBinder = (ValueBinder) jdbcTypeDescriptor.getBinder( enumValueConverter.getRelationalJavaDescriptor() );
}
if ( LOG.isDebugEnabled() ) {
@ -217,7 +228,7 @@ public class EnumType<T extends Enum<T>>
return null;
}
private EnumValueConverter<T,?> interpretParameters(Properties parameters) {
private EnumValueConverter<T,Object> interpretParameters(Properties parameters) {
//noinspection rawtypes
final EnumJavaTypeDescriptor enumJavaDescriptor = (EnumJavaTypeDescriptor) typeConfiguration
.getJavaTypeDescriptorRegistry()
@ -349,14 +360,14 @@ public class EnumType<T extends Enum<T>>
}
@Override
public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws SQLException {
throw new NotYetImplementedFor6Exception( getClass() );
// verifyConfigured();
// return enumValueConverter.readValue( rs, names[0], session );
public Object nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, Object owner) throws SQLException {
verifyConfigured();
final Object relational = jdbcValueExtractor.extract( rs, position, session );
return enumValueConverter.toDomainValue( relational );
}
private void verifyConfigured() {
if ( enumValueConverter == null ) {
if ( enumValueConverter == null || jdbcValueBinder == null || jdbcValueExtractor == null ) {
throw new AssertionFailure( "EnumType (" + enumClass.getName() + ") not properly, fully configured" );
}
}

View File

@ -5,9 +5,15 @@
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.type;
import java.sql.Types;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.StringTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.ClobTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.type.spi.TypeConfiguration;
/**
* A type that maps between {@link java.sql.Types#CLOB CLOB} and {@link String}
@ -18,7 +24,7 @@ import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
*/
public class MaterializedClobType
extends AbstractSingleColumnStandardBasicType<String>
implements SqlTypeDescriptorIndicatorCapable<String> {
implements AdjustableBasicType<String> {
public static final MaterializedClobType INSTANCE = new MaterializedClobType();
public MaterializedClobType() {
@ -30,10 +36,18 @@ public class MaterializedClobType
}
@Override
public <X> BasicType<X> resolveIndicatedType(JdbcTypeDescriptorIndicators indicators) {
public <X> BasicType<X> resolveIndicatedType(
JdbcTypeDescriptorIndicators indicators,
JavaTypeDescriptor<X> domainJtd) {
if ( indicators.isNationalized() ) {
//noinspection unchecked
return (BasicType<X>) MaterializedNClobType.INSTANCE;
final TypeConfiguration typeConfiguration = indicators.getTypeConfiguration();
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeDescriptorRegistry();
final JdbcTypeDescriptor nclobType = jdbcTypeRegistry.getDescriptor( Types.NCLOB );
return typeConfiguration.getBasicTypeRegistry().resolve(
domainJtd,
nclobType
);
}
//noinspection unchecked

View File

@ -0,0 +1,28 @@
/*
* 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.type;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
/**
* Handles conversion to/from Boolean as `0` (false) or `1` (true)
*
* @author Steve Ebersole
*/
@Converter
public class NumericBooleanConverter implements AttributeConverter<Boolean,Integer> {
@Override
public Integer convertToDatabaseColumn(Boolean attribute) {
return NumericBooleanType.NumericConverter.toRelational( attribute );
}
@Override
public Boolean convertToEntityAttribute(Integer dbData) {
return NumericBooleanType.NumericConverter.toDomain( dbData );
}
}

View File

@ -60,9 +60,18 @@ public class NumericBooleanType
return CONVERTER;
}
private static class NumericConverter implements BasicValueConverter<Boolean, Integer> {
public static class NumericConverter implements BasicValueConverter<Boolean, Integer> {
/**
* Singleton access
*/
public static final NumericConverter INSTANCE = new NumericConverter();
@Override
public Boolean toDomainValue(Integer relationalForm) {
return toDomain( relationalForm );
}
public static Boolean toDomain(Integer relationalForm) {
if ( relationalForm == null ) {
return null;
}
@ -80,6 +89,10 @@ public class NumericBooleanType
@Override
public Integer toRelationalValue(Boolean domainForm) {
return toRelational( domainForm );
}
public static Integer toRelational(Boolean domainForm) {
if ( domainForm == null ) {
return null;
}

View File

@ -5,9 +5,14 @@
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.type;
import java.sql.Types;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.PrimitiveCharacterArrayTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.ClobTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.type.spi.TypeConfiguration;
/**
* Map a char[] to a Clob
@ -16,7 +21,7 @@ import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
*/
public class PrimitiveCharacterArrayClobType
extends AbstractSingleColumnStandardBasicType<char[]>
implements SqlTypeDescriptorIndicatorCapable<char[]> {
implements AdjustableBasicType<char[]> {
public static final CharacterArrayClobType INSTANCE = new CharacterArrayClobType();
public PrimitiveCharacterArrayClobType() {
@ -29,13 +34,20 @@ public class PrimitiveCharacterArrayClobType
}
@Override
public <X> BasicType<X> resolveIndicatedType(JdbcTypeDescriptorIndicators indicators) {
if ( indicators.isNationalized() ) {
//noinspection unchecked
return (BasicType<X>) PrimitiveCharacterArrayNClobType.INSTANCE;
@SuppressWarnings("unchecked")
public <X> BasicType<X> resolveIndicatedType(
JdbcTypeDescriptorIndicators indicators,
JavaTypeDescriptor<X> domainJtd) {
if ( ! indicators.isNationalized() ) {
return (BasicType<X>) this;
}
//noinspection unchecked
return (BasicType<X>) this;
final TypeConfiguration typeConfiguration = indicators.getTypeConfiguration();
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeDescriptorRegistry();
return typeConfiguration.getBasicTypeRegistry().resolve(
domainJtd,
jdbcTypeRegistry.getDescriptor( Types.NCLOB )
);
}
}

View File

@ -5,7 +5,10 @@
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.type;
import java.io.Serializable;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
import org.hibernate.type.spi.TypeConfiguration;
/**
* Additional contract for primitive / primitive wrapper types.
@ -13,14 +16,14 @@ import java.io.Serializable;
* @author Gavin King
* @author Steve Ebersole
*/
public interface PrimitiveType<T> extends LiteralType<T> {
public interface PrimitiveType<T> extends LiteralType<T>, AdjustableBasicType<T> {
/**
* Retrieve the primitive counterpart to the wrapper type identified by
* {@link org.hibernate.type.Type#getReturnedClass()}.
*
* @return The primitive Java type.
*/
public abstract Class getPrimitiveClass();
Class<?> getPrimitiveClass();
/**
* Retrieve the string representation of the given value.
@ -29,12 +32,18 @@ public interface PrimitiveType<T> extends LiteralType<T> {
*
* @return The string representation
*/
public String toString(T value);
String toString(T value);
/**
* Get this type's default value.
*
* @return The default value.
*/
public abstract Object getDefaultValue();
Object getDefaultValue();
@Override
default <X> BasicType<X> resolveIndicatedType(JdbcTypeDescriptorIndicators indicators, JavaTypeDescriptor<X> domainJtd) {
final TypeConfiguration typeConfiguration = indicators.getTypeConfiguration();
return typeConfiguration.getBasicTypeRegistry().resolve( domainJtd, getJdbcTypeDescriptor() );
}
}

View File

@ -8,19 +8,21 @@ package org.hibernate.type;
import java.io.Serializable;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.SerializableTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.VarbinaryTypeDescriptor;
/**
* A type that maps between a {@link java.sql.Types#VARBINARY VARBINARY} and {@link Serializable} classes.
* <p/>
* Notice specifically the 2 forms:<ul>
* <li>{@link #INSTANCE} indicates a mapping using the {@link Serializable} interface itself.</li>
* <li>{@link #SerializableType(Class)} indicates a mapping using the specific class</li>
* Notice specifically the 3 constructors:<ul>
* <li>{@link #INSTANCE} indicates a mapping using the {@link Serializable} interface itself.</li>
* <li>{@link #SerializableType(Class)} indicates a mapping using the specific class</li>
* <li>{@link #SerializableType(JavaTypeDescriptor)} indicates a mapping using the specific JavaTypeDescriptor</li>
* </ul>
* The important distinction has to do with locating the appropriate {@link ClassLoader} to use during deserialization.
* In the fist form we are always using the {@link ClassLoader} of the JVM (Hibernate will always fallback to trying
* its classloader as well). The second form is better at targeting the needed {@link ClassLoader} actually needed.
* its classloader as well). The second and third forms are better at targeting the needed {@link ClassLoader} actually needed.
*
* @author Gavin King
* @author Steve Ebersole
@ -35,6 +37,11 @@ public class SerializableType<T extends Serializable> extends AbstractSingleColu
this.serializableClass = serializableClass;
}
public SerializableType(JavaTypeDescriptor<T> jtd) {
super( VarbinaryTypeDescriptor.INSTANCE, jtd );
this.serializableClass = jtd.getJavaTypeClass();
}
public String getName() {
return (serializableClass==Serializable.class) ? "serializable" : serializableClass.getName();
}

View File

@ -5,10 +5,15 @@
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.type;
import java.sql.Types;
import org.hibernate.dialect.Dialect;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.StringTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
import org.hibernate.type.descriptor.jdbc.VarcharTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.type.spi.TypeConfiguration;
/**
* A type that maps between {@link java.sql.Types#VARCHAR VARCHAR} and {@link String}
@ -18,7 +23,7 @@ import org.hibernate.type.descriptor.jdbc.VarcharTypeDescriptor;
*/
public class StringType
extends AbstractSingleColumnStandardBasicType<String>
implements DiscriminatorType<String>, SqlTypeDescriptorIndicatorCapable<String> {
implements DiscriminatorType<String>, AdjustableBasicType<String> {
public static final StringType INSTANCE = new StringType();
@ -47,14 +52,33 @@ public class StringType
return value;
}
@SuppressWarnings({"rawtypes", "unchecked"})
@Override
public BasicType resolveIndicatedType(JdbcTypeDescriptorIndicators indicators) {
@SuppressWarnings("unchecked")
public <X> BasicType<X> resolveIndicatedType(
JdbcTypeDescriptorIndicators indicators,
JavaTypeDescriptor<X> domainJtd) {
if ( ! indicators.isLob() && ! indicators.isNationalized() ) {
return (BasicType<X>) this;
}
final TypeConfiguration typeConfiguration = indicators.getTypeConfiguration();
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeDescriptorRegistry();
final int jdbcTypeCode;
if ( indicators.isLob() ) {
return indicators.isNationalized() ? MaterializedNClobType.INSTANCE : MaterializedClobType.INSTANCE;
jdbcTypeCode = indicators.isNationalized()
? Types.NCLOB
: Types.CLOB;
}
else {
return indicators.isNationalized() ? StringNVarcharType.INSTANCE : this;
jdbcTypeCode = indicators.isNationalized()
? Types.NVARCHAR
: Types.VARCHAR;
}
return typeConfiguration.getBasicTypeRegistry().resolve(
domainJtd,
jdbcTypeRegistry.getDescriptor( jdbcTypeCode )
);
}
}

View File

@ -5,6 +5,7 @@
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.type;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.StringTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.LongVarcharTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
@ -18,7 +19,7 @@ import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
*/
public class TextType
extends AbstractSingleColumnStandardBasicType<String>
implements SqlTypeDescriptorIndicatorCapable<String> {
implements AdjustableBasicType<String> {
public static final TextType INSTANCE = new TextType();
public TextType() {
@ -30,7 +31,9 @@ public class TextType
}
@Override
public <X> BasicType<X> resolveIndicatedType(JdbcTypeDescriptorIndicators indicators) {
public <X> BasicType<X> resolveIndicatedType(
JdbcTypeDescriptorIndicators indicators,
JavaTypeDescriptor<X> domainJtd) {
if ( indicators.isNationalized() ) {
//noinspection unchecked
return (BasicType<X>) NTextType.INSTANCE;

View File

@ -0,0 +1,28 @@
/*
* 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.type;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
/**
* Handles conversion to/from Boolean as `T` or `F`
*
* @author Steve Ebersole
*/
@Converter
public class TrueFalseConverter implements AttributeConverter<Boolean,Character> {
@Override
public Character convertToDatabaseColumn(Boolean attribute) {
return TrueFalseType.TrueFalseConverter.toRelational( attribute );
}
@Override
public Boolean convertToEntityAttribute(Character dbData) {
return TrueFalseType.TrueFalseConverter.toDomain( dbData );
}
}

View File

@ -68,9 +68,18 @@ public class TrueFalseType
return CONVERTER;
}
private static class TrueFalseConverter implements BasicValueConverter<Boolean, Character> {
public static class TrueFalseConverter implements BasicValueConverter<Boolean, Character> {
/**
* Singleton access
*/
public static final TrueFalseConverter INSTANCE = new TrueFalseConverter();
@Override
public Boolean toDomainValue(Character relationalForm) {
return toDomain( relationalForm );
}
public static Boolean toDomain(Character relationalForm) {
if ( relationalForm == null ) {
return null;
}
@ -88,6 +97,10 @@ public class TrueFalseType
@Override
public Character toRelationalValue(Boolean domainForm) {
return toRelational( domainForm );
}
public static Character toRelational(Boolean domainForm) {
if ( domainForm == null ) {
return null;
}

Some files were not shown because too many files have changed in this diff Show More