HHH-14856 - Introduce @CustomType;
HHH-14865 - Re-work @Any and @ManyToAny support; HHH-14863 - Compositional definition of basic value mappings; HHH-14864 - Drop legacy Type-based annotations * documentation work * support for using most of the new mapping annotations related to basic and any mappings as meta-annotations * support for `@Mutability` on AttributeConverter implementations * additional tests in the User Guide's BitSet mapping Case Study
This commit is contained in:
parent
abc8225e9d
commit
ede52e9aba
|
@ -201,7 +201,7 @@ First, we need to extend the `AbstractSingleColumnStandardBasicType` like this:
|
|||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/basic/BitSetType.java[tags=basic-custom-type-BitSetType-example]
|
||||
include::{sourcedir}/basic/bitset/BitSetType.java[tags=basic-custom-type-BitSetType-example]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -214,7 +214,7 @@ On the Java side, we need to use a `BitSetJavaType` instance which can be implem
|
|||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/basic/BitSetTypeDescriptor.java[tags=basic-custom-type-BitSetTypeDescriptor-example]
|
||||
include::{sourcedir}/basic/bitset/BitSetTypeDescriptor.java[tags=basic-custom-type-BitSetTypeDescriptor-example]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -227,7 +227,7 @@ The `BasicType` must be registered, and this can be done at bootstrapping time:
|
|||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/basic/BitSetTypeTest.java[tags=basic-custom-type-register-BasicType-example]
|
||||
include::{sourcedir}/basic/bitset/BitSetTypeTest.java[tags=basic-custom-type-register-BasicType-example]
|
||||
----
|
||||
|
||||
or using the `MetadataBuilder`
|
||||
|
@ -245,7 +245,7 @@ With the new `BitSetType` being registered as `bitset`, the entity mapping looks
|
|||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/basic/BitSetTypeTest.java[tags=basic-custom-type-BitSetType-mapping-example]
|
||||
include::{sourcedir}/basic/bitset/BitSetTypeTest.java[tags=basic-custom-type-BitSetType-mapping-example]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -256,7 +256,7 @@ Alternatively, you can use the `@TypeDef` and skip the registration phase:
|
|||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/basic/BitSetTypeDefTest.java[tags=basic-custom-type-BitSetTypeDef-mapping-example]
|
||||
include::{sourcedir}/basic/bitset/BitSetTypeDefTest.java[tags=basic-custom-type-BitSetTypeDef-mapping-example]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -267,7 +267,7 @@ To validate this new `BasicType` implementation, we can test it as follows:
|
|||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/basic/BitSetTypeTest.java[tags=basic-custom-type-BitSetType-persistence-example]
|
||||
include::{sourcedir}/basic/bitset/BitSetTypeTest.java[tags=basic-custom-type-BitSetType-persistence-example]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -335,7 +335,7 @@ Without registering a name, the `UserType` mapping requires the fully qualified
|
|||
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
@Type( type = "org.hibernate.userguide.mapping.basic.BitSetUserType" )
|
||||
@Type( type = "org.hibernate.userguide.mapping.basic.bitset.BitSetUserType" )
|
||||
----
|
||||
====
|
||||
|
||||
|
|
|
@ -501,12 +501,51 @@ a metadata information for the associated entity type.
|
|||
This is not the usual way of mapping polymorphic associations and you should use this only in special cases (e.g. audit logs, user session data, etc).
|
||||
====
|
||||
|
||||
The `@Any` annotation describes the column holding the metadata information.
|
||||
To link the value of the metadata information and an actual entity type, the `@AnyDef` and `@AnyDefs` annotations are used.
|
||||
The `metaType` attribute allows the application to specify a custom type that maps database column values to persistent classes that have identifier properties of the type specified by `idType`.
|
||||
You must specify the mapping from values of the `metaType` to class names.
|
||||
To map such an association, Hibernate needs to understand 3 things:
|
||||
|
||||
For the next examples, consider the following `Property` class hierarchy:
|
||||
1. The column and mapping for the discriminator
|
||||
2. The column and mapping for the key
|
||||
3. The mapping between discriminator values and entity classes
|
||||
|
||||
|
||||
[[associations-any-discriminator]]
|
||||
===== The discriminator
|
||||
|
||||
The discriminator of an any-style association holds the value that indicates which entity is
|
||||
referred to by a row.
|
||||
|
||||
Its "column" can be specified with either `@Column` or `@Formula`. The mapping type can be influenced by any of:
|
||||
|
||||
1. `@AnyDiscriminator` allows re-using the `DiscriminatorType` simplified mappings from Jakarta Persistence for the common cases
|
||||
2. `@JavaType`
|
||||
3. `@JdbcType`
|
||||
4. `@JdbcTypeCode`
|
||||
|
||||
|
||||
[[associations-any-key]]
|
||||
===== The key
|
||||
|
||||
The key of an any-style association holds the matching key for the row
|
||||
|
||||
Its "column" can be specified with either `@JoinColumn` (`@JoinFormula` not supported). The mapping
|
||||
type can be influenced by any of:
|
||||
|
||||
1. `@AnyKeyJavaClass`
|
||||
2. `@AnyKeyJavaType`
|
||||
3. `@AnyKeyJdbcType`
|
||||
4. `@AnyKeyJdbcTypeCode`
|
||||
|
||||
|
||||
[[associations-any-values]]
|
||||
===== The discriminator value mappings
|
||||
|
||||
`@AnyDiscriminatorValue` is used to map the discriminator values to the corresponding entity classes
|
||||
|
||||
|
||||
[[associations-any-property]]
|
||||
==== Example using @Any mapping
|
||||
|
||||
For this example, consider the following `Property` class hierarchy:
|
||||
|
||||
[[associations-any-property-example]]
|
||||
.`Property` class hierarchy
|
||||
|
@ -521,7 +560,7 @@ include::{sourcedir}/any/StringProperty.java[tags=associations-any-property-exam
|
|||
----
|
||||
====
|
||||
|
||||
A `PropertyHolder` can reference any such property, and, because each `Property` belongs to a separate table, the `@Any` annotation is, therefore, required.
|
||||
A `PropertyHolder` entity defines an attribute of type `Property`:
|
||||
|
||||
[[associations-any-example]]
|
||||
.`@Any` mapping usage
|
||||
|
@ -537,28 +576,13 @@ include::{extrasdir}/associations-any-example.sql[]
|
|||
----
|
||||
====
|
||||
|
||||
`PropertyHolder#property` can refer to either `StringProperty` or `IntegerProperty` references, as indicated
|
||||
by the associated discriminator according to the `@DiscriminatorValue` annotations.
|
||||
|
||||
As you can see, there are two columns used to reference a `Property` instance: `property_id` and `property_type`.
|
||||
The `property_id` is used to match the `id` column of either the `string_property` or `integer_property` tables,
|
||||
while the `property_type` is used to match the `string_property` or the `integer_property` table.
|
||||
|
||||
The table resolving mapping is defined by the `metaDef` attribute which references an `@AnyMetaDef` mapping.
|
||||
|
||||
The `package-info.java` contains the `@AnyMetaDef` mapping:
|
||||
|
||||
[[associations-any-meta-def-example]]
|
||||
.`@AnyMetaDef` mapping usage
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/any/package-info.java[tags=associations-any-meta-def-example]
|
||||
----
|
||||
====
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Although the `@AnyMetaDef` mapping could be set right next to the `@Any` annotation, it is good practice to configure it at the class or package level, especially if you need to reuse it for multiple `@Any` mappings.
|
||||
====
|
||||
|
||||
To see the `@Any` annotation in action, consider the next examples.
|
||||
|
||||
If we persist an `IntegerProperty` as well as a `StringProperty` entity, and associate
|
||||
|
@ -596,12 +620,45 @@ include::{extrasdir}/associations-any-query-example.sql[]
|
|||
----
|
||||
====
|
||||
|
||||
|
||||
[[associations-any-meta-annotations]]
|
||||
===== Using meta-annotations
|
||||
|
||||
As mentioned in <<basic-mapping>>, Hibernate's ANY-related annotations can be composed using meta-annotations
|
||||
to re-use ANY mapping details.
|
||||
|
||||
Looking back at <<associations-any-example>>, we can see how cumbersome it would be to duplicate that
|
||||
information every time `Property` is mapped in the domain model. This description can also be moved
|
||||
into a single annotation that we can apply in each usage.
|
||||
|
||||
|
||||
[[associations-any-composed-example]]
|
||||
.`@Any` mapping usage
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/any/PropertyHolder2.java[tags=associations-any-def-example]
|
||||
----
|
||||
====
|
||||
|
||||
Though the mapping has been "simplified", the mapping works exactly as shown in <<associations-any-example>>.
|
||||
|
||||
|
||||
|
||||
|
||||
[[associations-many-to-any]]
|
||||
===== `@ManyToAny` mapping
|
||||
|
||||
While the `@Any` mapping is useful to emulate a `@ManyToOne` association when there can be multiple target entities,
|
||||
to emulate a `@OneToMany` association, the `@ManyToAny` annotation must be used.
|
||||
|
||||
The mapping details are the same between `@Any` and `@ManyToAny` except for:
|
||||
|
||||
1. The use of `@ManyToAny` instead of `@Any`
|
||||
2. The use of `@JoinTable`, `@JoinTable#joinColumns` and `@JoinTable#inverseJoinColumns` instead
|
||||
of just `@JoinColumn`
|
||||
|
||||
|
||||
In the following example, the `PropertyRepository` entity has a collection of `Property` entities.
|
||||
|
||||
The `repository_properties` link table holds the associations between `PropertyRepository` and `Property` entities.
|
||||
|
@ -657,6 +714,8 @@ include::{extrasdir}/associations-many-to-any-query-example.sql[]
|
|||
----
|
||||
====
|
||||
|
||||
|
||||
|
||||
[[associations-JoinFormula]]
|
||||
==== `@JoinFormula` mapping
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ Generally, the `@Basic` annotation can be ignored as it is assumed by default.
|
|||
examples are ultimately the same.
|
||||
|
||||
[[basic-annotation-explicit-example]]
|
||||
.`@Basic` declared explicitly
|
||||
.`@Basic` explicit
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
|
@ -163,7 +163,7 @@ include::{extrasdir}/basic/mapping-column-formula-persistence-example.sql[]
|
|||
|
||||
[NOTE]
|
||||
====
|
||||
The SQL fragment defined by the `@Formula` annotation can be as complex as you want, and it can even include subselects.
|
||||
The SQL fragment defined by the `@Formula` annotation can be as complex as you want, and it can even include sub-selects.
|
||||
====
|
||||
|
||||
|
||||
|
@ -206,6 +206,12 @@ This includes removal of the following deprecated legacy annotations:
|
|||
See the 6.0 migration guide for discussions about migrating uses of these annotations
|
||||
====
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
The new annotations added as part of 6.0 support composing mappings in annotations
|
||||
through "meta-annotations".
|
||||
====
|
||||
|
||||
|
||||
Looking at <<basic-annotation-implicit-example, this example>>, how does Hibernate know what mapping
|
||||
to use for these attributes? The annotations do not really provide much information.
|
||||
|
@ -1555,160 +1561,6 @@ a Java service (see `java.util.ServiceLoader`).
|
|||
|
||||
|
||||
|
||||
|
||||
[[basic-bitset]]
|
||||
==== Case Study : BitSet
|
||||
|
||||
We've covered many ways to specify basic value mappings so far. This section will look at mapping the
|
||||
`java.util.BitSet` type by applying the different techniques covered so far.
|
||||
|
||||
[[basic-bitset-example-implicit]]
|
||||
.Implicit BitSet mapping
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/basic/BitSetImplicitTests.java[tags=basic-bitset-example-implicit]
|
||||
----
|
||||
====
|
||||
|
||||
As mentioned previously, the worst-case fallback for Hibernate mapping a basic type
|
||||
which implements `Serializable` is to simply serialize it to the database. BitSet
|
||||
does implement `Serializable`, so by default Hibernate would handle this mapping by serialization.
|
||||
|
||||
That is not an ideal mapping. In the following sections we will look at approaches to change
|
||||
various aspects of how the BitSet gets mapped to the database.
|
||||
|
||||
|
||||
[[basic-bitset-converter]]
|
||||
===== Using `AttributeConverter`
|
||||
|
||||
We've seen uses of `AttributeConverter` previously.
|
||||
|
||||
This works well in most cases and is portable across Jakarta Persistence providers.
|
||||
|
||||
[[basic-bitset-example-converter]]
|
||||
.BitSet AttributeConverter
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/basic/BitSetConverterTests.java[tags=basic-bitset-example-convert]
|
||||
|
||||
include::{sourcedir}/basic/BitSetConverterTests.java[tags=basic-bitset-example-converter]
|
||||
----
|
||||
====
|
||||
|
||||
The `@Convert` annotation was used for illustration. Generally such a converter would be auto-applied instead
|
||||
|
||||
See <<basic-jpa-convert>> for details.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
The use of `AttributeConverter` can have drawbacks related to Hibernate being able
|
||||
to appropriately handle the mutability aspects of the converted values. `AttributeConverter`
|
||||
does not indicate whether the converted values are mutable or not, so Hibernate has to assume
|
||||
they are (the safer assumption) which can lead to excessive conversions back and forth as part
|
||||
of dirty-checking as well as second-level caching.
|
||||
|
||||
See <<basic-jpa-convert-mutability>> for additional details.
|
||||
====
|
||||
|
||||
|
||||
[[basic-bitset-java-type]]
|
||||
===== Using a custom `JavaTypeDescriptor`
|
||||
|
||||
As covered in <<basic-mapping-explicit>>, we will define a `JavaTypeDescriptor`
|
||||
for `BitSet` that maps values to `VARCHAR` for storage by default.
|
||||
|
||||
[[basic-bitset-example-java-type]]
|
||||
.BitSet JavaTypeDescriptor
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/basic/BitSetJavaType.java[tags=basic-bitset-example-java-type]
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
We can either apply that type locally using `@JavaType`
|
||||
|
||||
[[basic-bitset-example-java-type-local]]
|
||||
.@JavaType
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/basic/BitSetJavaTypeTests.java[tags=basic-bitset-example-java-type-local,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
Or we can apply it globally using `@JavaTypeRegistration`. This allows the registered `JavaTypeDescriptor`
|
||||
to be used as the default whenever we encounter the `BitSet` type
|
||||
|
||||
[[basic-bitset-example-java-type-global]]
|
||||
.@JavaTypeRegistration
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/basic/BitSetJavaTypeRegistrationTests.java[tags=basic-bitset-example-java-type-global,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
[[basic-bitset-jdbc-type]]
|
||||
===== Selecting different `JdbcTypeDescriptor`
|
||||
|
||||
Our custom `BitSetJavaType` maps `BitSet` values to `VARCHAR` by default. That was a better option
|
||||
than direct serialization. But as `BitSet` is ultimately binary data we would probably really want to
|
||||
map this to `VARBINARY` type instead. One way to do that would be to change `BitSetJavaType#getRecommendedJdbcType`
|
||||
to instead return `VARBINARY` descriptor. Another option would be to use a local `@JdbcType` or `@JdbcTypeCode`.
|
||||
|
||||
The following examples for specifying the `JdbcTypeDescriptor` assume our `BitSetJavaType`
|
||||
is globally registered.
|
||||
|
||||
We will again store the values as `VARBINARY` in the database. The difference now however is that
|
||||
the coercion methods `#wrap` and `#unwrap` will be used to prepare the value rather than relying on
|
||||
serialization.
|
||||
|
||||
|
||||
[[basic-bitset-example-jdbc-type-code]]
|
||||
.@JdbcTypeCode
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/basic/BitSetJdbcTypeCodeTests.java[tags=basic-bitset-example-jdbc-type-code,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
In this example, `@JdbcTypeCode` has been used to indicate that the `JdbcTypeDescriptor` registered for JDBC's
|
||||
`VARBINARY` type should be used.
|
||||
|
||||
|
||||
[[basic-bitset-example-jdbc-type-local]]
|
||||
.@JdbcType
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/basic/BitSetJdbcTypeTests.java[tags=basic-bitset-example-jdbc-type-local,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
In this example, `@JdbcType` has been used to specify our custom `BitSetJdbcType` descriptor locally for
|
||||
this attribute.
|
||||
|
||||
We could instead replace how Hibernate deals with all `VARBINARY` handling with our custom impl using
|
||||
`@JdbcTypeRegistration`
|
||||
|
||||
[[basic-bitset-example-jdbc-type-global]]
|
||||
.@JdbcType
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/basic/BitSetJdbcTypeRegistrationTests.java[tags=basic-bitset-example-jdbc-type-global,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
[[basic-jpa-convert]]
|
||||
|
@ -1953,7 +1805,156 @@ By passing the associated Hibernate `Type`, you can use the `Caption` object whe
|
|||
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
[[basic-bitset]]
|
||||
==== Case Study : BitSet
|
||||
|
||||
We've covered many ways to specify basic value mappings so far. This section will look at mapping the
|
||||
`java.util.BitSet` type by applying the different techniques covered so far.
|
||||
|
||||
[[basic-bitset-example-implicit]]
|
||||
.Implicit BitSet mapping
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/basic/bitset/BitSetImplicitTests.java[tags=basic-bitset-example-implicit]
|
||||
----
|
||||
====
|
||||
|
||||
As mentioned previously, the worst-case fallback for Hibernate mapping a basic type
|
||||
which implements `Serializable` is to simply serialize it to the database. BitSet
|
||||
does implement `Serializable`, so by default Hibernate would handle this mapping by serialization.
|
||||
|
||||
That is not an ideal mapping. In the following sections we will look at approaches to change
|
||||
various aspects of how the BitSet gets mapped to the database.
|
||||
|
||||
|
||||
[[basic-bitset-converter]]
|
||||
===== Using `AttributeConverter`
|
||||
|
||||
We've seen uses of `AttributeConverter` previously.
|
||||
|
||||
This works well in most cases and is portable across Jakarta Persistence providers.
|
||||
|
||||
[[basic-bitset-example-converter]]
|
||||
.BitSet AttributeConverter
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/basic/bitset/BitSetConverterTests.java[tags=basic-bitset-example-convert]
|
||||
|
||||
include::{sourcedir}/basic/bitset/BitSetConverterTests.java[tags=basic-bitset-example-converter]
|
||||
----
|
||||
====
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
The `@Convert` annotation was used for illustration. Generally such a converter would be auto-applied instead
|
||||
|
||||
See <<basic-jpa-convert>> for details.
|
||||
====
|
||||
|
||||
This greatly improves the reading and writing performance of dealing with these
|
||||
BitSet values because the `AttributeConverter` does that more efficiently using
|
||||
a simple externalizable form of the BitSet rather than serializing and deserializing
|
||||
the values.
|
||||
|
||||
See also <<basic-jpa-convert-mutability>>.
|
||||
|
||||
|
||||
[[basic-bitset-java-type]]
|
||||
===== Using a custom `JavaTypeDescriptor`
|
||||
|
||||
As covered in <<basic-mapping-explicit>>, we will define a `JavaTypeDescriptor`
|
||||
for `BitSet` that maps values to `VARCHAR` for storage by default.
|
||||
|
||||
[[basic-bitset-example-java-type]]
|
||||
.BitSet JavaTypeDescriptor
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/basic/bitset/BitSetJavaType.java[tags=basic-bitset-example-java-type]
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
We can either apply that type locally using `@JavaType`
|
||||
|
||||
[[basic-bitset-example-java-type-local]]
|
||||
.@JavaType
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/basic/bitset/BitSetJavaTypeTests.java[tags=basic-bitset-example-java-type-local,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
Or we can apply it globally using `@JavaTypeRegistration`. This allows the registered `JavaTypeDescriptor`
|
||||
to be used as the default whenever we encounter the `BitSet` type
|
||||
|
||||
[[basic-bitset-example-java-type-global]]
|
||||
.@JavaTypeRegistration
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/basic/bitset/BitSetJavaTypeRegistrationTests.java[tags=basic-bitset-example-java-type-global,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
[[basic-bitset-jdbc-type]]
|
||||
===== Selecting different `JdbcTypeDescriptor`
|
||||
|
||||
Our custom `BitSetJavaType` maps `BitSet` values to `VARCHAR` by default. That was a better option
|
||||
than direct serialization. But as `BitSet` is ultimately binary data we would probably really want to
|
||||
map this to `VARBINARY` type instead. One way to do that would be to change `BitSetJavaType#getRecommendedJdbcType`
|
||||
to instead return `VARBINARY` descriptor. Another option would be to use a local `@JdbcType` or `@JdbcTypeCode`.
|
||||
|
||||
The following examples for specifying the `JdbcTypeDescriptor` assume our `BitSetJavaType`
|
||||
is globally registered.
|
||||
|
||||
We will again store the values as `VARBINARY` in the database. The difference now however is that
|
||||
the coercion methods `#wrap` and `#unwrap` will be used to prepare the value rather than relying on
|
||||
serialization.
|
||||
|
||||
|
||||
[[basic-bitset-example-jdbc-type-code]]
|
||||
.@JdbcTypeCode
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/basic/bitset/BitSetJdbcTypeCodeTests.java[tags=basic-bitset-example-jdbc-type-code,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
In this example, `@JdbcTypeCode` has been used to indicate that the `JdbcTypeDescriptor` registered for JDBC's
|
||||
`VARBINARY` type should be used.
|
||||
|
||||
|
||||
[[basic-bitset-example-jdbc-type-local]]
|
||||
.@JdbcType
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/basic/bitset/BitSetJdbcTypeTests.java[tags=basic-bitset-example-jdbc-type-local,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
In this example, `@JdbcType` has been used to specify our custom `BitSetJdbcType` descriptor locally for
|
||||
this attribute.
|
||||
|
||||
We could instead replace how Hibernate deals with all `VARBINARY` handling with our custom impl using
|
||||
`@JdbcTypeRegistration`
|
||||
|
||||
[[basic-bitset-example-jdbc-type-global]]
|
||||
.@JdbcType
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/basic/bitset/BitSetJdbcTypeRegistrationTests.java[tags=basic-bitset-example-jdbc-type-global,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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.associations.any;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.hibernate.annotations.AnyDiscriminator;
|
||||
import org.hibernate.annotations.AnyDiscriminatorValue;
|
||||
import org.hibernate.annotations.AnyKeyJavaClass;
|
||||
|
||||
import jakarta.persistence.DiscriminatorType;
|
||||
|
||||
|
||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
||||
@AnyDiscriminator( DiscriminatorType.STRING )
|
||||
@AnyKeyJavaClass( Long.class )
|
||||
|
||||
@AnyDiscriminatorValue( discriminator = "S", entity = StringProperty.class )
|
||||
@AnyDiscriminatorValue( discriminator = "I", entity = IntegerProperty.class )
|
||||
public @interface PropertyDiscriminationDef {
|
||||
}
|
|
@ -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.associations.any;
|
||||
|
||||
import org.hibernate.annotations.Any;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
//tag::associations-any-def-example[]
|
||||
@Entity
|
||||
@Table( name = "property_holder" )
|
||||
public class PropertyHolder2 {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@Any
|
||||
@PropertyDiscriminationDef
|
||||
@Column( name = "property_type" )
|
||||
@JoinColumn( name = "property_id" )
|
||||
private Property property;
|
||||
|
||||
//Getters and setters are omitted for brevity
|
||||
|
||||
//end::associations-any-def-example[]
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Property getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
public void setProperty(Property property) {
|
||||
this.property = property;
|
||||
}
|
||||
//tag::associations-any-def-example[]
|
||||
}
|
||||
//end::associations-any-def-example[]
|
|
@ -43,7 +43,7 @@ import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
|
|||
import org.hibernate.jpa.boot.internal.PersistenceUnitInfoDescriptor;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
|
||||
import org.hibernate.userguide.mapping.basic.BitSetUserType;
|
||||
import org.hibernate.userguide.mapping.basic.bitset.BitSetUserType;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
|
|
@ -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.bitset;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.util.BitSet;
|
||||
|
||||
import org.hibernate.annotations.Immutable;
|
||||
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.type.descriptor.java.ImmutableMutabilityPlan;
|
||||
import org.hibernate.type.descriptor.java.MutabilityPlan;
|
||||
|
||||
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 jakarta.persistence.AttributeConverter;
|
||||
import jakarta.persistence.Convert;
|
||||
import jakarta.persistence.Converter;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import org.assertj.core.api.Assertions;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.isOneOf;
|
||||
|
||||
/**
|
||||
* Test using a converter to map the BitSet
|
||||
*/
|
||||
@DomainModel( annotatedClasses = BitSetConverterImmutableTests.Product.class )
|
||||
@SessionFactory
|
||||
public class BitSetConverterImmutableTests {
|
||||
|
||||
@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 ) );
|
||||
|
||||
Assertions.assertThat( attributeMapping.getExposedMutabilityPlan() ).isNotInstanceOf( BitSetMutabilityPlan.class );
|
||||
Assertions.assertThat( attributeMapping.getExposedMutabilityPlan() ).isInstanceOf( ImmutableMutabilityPlan.class );
|
||||
Assertions.assertThat( attributeMapping.getExposedMutabilityPlan().isMutable() ).isFalse();
|
||||
|
||||
final BitSet sample = new BitSet();
|
||||
Assertions.assertThat( ( (MutabilityPlan) attributeMapping.getExposedMutabilityPlan() ).deepCopy( sample ) ).isSameAs( sample );
|
||||
|
||||
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[]
|
||||
@Immutable
|
||||
@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[]
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* 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.bitset;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.util.BitSet;
|
||||
|
||||
import org.hibernate.annotations.Mutability;
|
||||
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 jakarta.persistence.AttributeConverter;
|
||||
import jakarta.persistence.Convert;
|
||||
import jakarta.persistence.Converter;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import org.assertj.core.api.Assertions;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.isOneOf;
|
||||
|
||||
/**
|
||||
* Basically the same test as {@link BitSetConverterTests} except here we
|
||||
* specify a mutability-plan on the converter to improve the deep-copying
|
||||
*/
|
||||
@DomainModel( annotatedClasses = BitSetConverterMutabilityTests.Product.class )
|
||||
@SessionFactory
|
||||
public class BitSetConverterMutabilityTests {
|
||||
|
||||
@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 ) );
|
||||
|
||||
Assertions.assertThat( attributeMapping.getExposedMutabilityPlan() ).isInstanceOf( BitSetMutabilityPlan.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 )
|
||||
@Mutability( BitSetMutabilityPlan.class )
|
||||
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[]
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* 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;
|
||||
package org.hibernate.userguide.mapping.basic.bitset;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.util.BitSet;
|
||||
|
@ -14,10 +14,10 @@ import jakarta.persistence.Converter;
|
|||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import org.assertj.core.api.Assertions;
|
||||
|
||||
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;
|
||||
|
@ -33,7 +33,7 @@ import static org.hamcrest.Matchers.instanceOf;
|
|||
import static org.hamcrest.Matchers.isOneOf;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
* Test using a converter to map the BitSet
|
||||
*/
|
||||
@DomainModel( annotatedClasses = BitSetConverterTests.Product.class )
|
||||
@SessionFactory
|
||||
|
@ -53,6 +53,8 @@ public class BitSetConverterTests {
|
|||
final JpaAttributeConverter converter = (JpaAttributeConverter) attributeMapping.getValueConverter();
|
||||
assertThat( converter.getConverterBean().getBeanClass(), equalTo( BitSetConverter.class ) );
|
||||
|
||||
Assertions.assertThat( attributeMapping.getExposedMutabilityPlan() ).isNotInstanceOf( BitSetMutabilityPlan.class );
|
||||
|
||||
assertThat(
|
||||
attributeMapping.getJdbcMapping().getJdbcTypeDescriptor().getJdbcTypeCode(),
|
||||
isOneOf( Types.VARCHAR, Types.NVARCHAR )
|
|
@ -4,7 +4,7 @@
|
|||
* 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;
|
||||
package org.hibernate.userguide.mapping.basic.bitset;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
* 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;
|
||||
package org.hibernate.userguide.mapping.basic.bitset;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.util.BitSet;
|
||||
|
@ -15,7 +15,6 @@ import jakarta.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;
|
||||
|
@ -23,13 +22,9 @@ 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;
|
||||
|
||||
/**
|
|
@ -1,4 +1,10 @@
|
|||
package org.hibernate.userguide.mapping.basic;
|
||||
/*
|
||||
* 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.bitset;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.util.BitSet;
|
|
@ -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.bitset;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
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 jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@DomainModel(
|
||||
annotatedClasses = BitSetJavaTypeContributionTests.Product.class,
|
||||
typeContributors = BitSetJavaTypeContributor.class
|
||||
)
|
||||
@SessionFactory
|
||||
public class BitSetJavaTypeContributionTests {
|
||||
|
||||
@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-contrib[]
|
||||
@Entity(name = "Product")
|
||||
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-contrib[]
|
||||
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-contrib[]
|
||||
}
|
||||
//end::basic-bitset-example-java-type-contrib[]
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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.bitset;
|
||||
|
||||
import org.hibernate.boot.model.TypeContributions;
|
||||
import org.hibernate.boot.model.TypeContributor;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class BitSetJavaTypeContributor implements TypeContributor {
|
||||
@Override
|
||||
public void contribute(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
|
||||
typeContributions.contributeJavaTypeDescriptor( BitSetJavaType.INSTANCE );
|
||||
}
|
||||
}
|
|
@ -4,10 +4,10 @@
|
|||
* 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;
|
||||
package org.hibernate.userguide.mapping.basic.bitset;
|
||||
|
||||
import java.util.BitSet;
|
||||
import jakarta.persistence.Basic;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
|
@ -4,10 +4,10 @@
|
|||
* 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;
|
||||
package org.hibernate.userguide.mapping.basic.bitset;
|
||||
|
||||
import java.util.BitSet;
|
||||
import jakarta.persistence.Basic;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
|
@ -4,7 +4,7 @@
|
|||
* 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;
|
||||
package org.hibernate.userguide.mapping.basic.bitset;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.util.BitSet;
|
|
@ -4,7 +4,7 @@
|
|||
* 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;
|
||||
package org.hibernate.userguide.mapping.basic.bitset;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.util.BitSet;
|
||||
|
@ -14,6 +14,7 @@ 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.userguide.mapping.basic.CustomBinaryJdbcType;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
|
@ -4,7 +4,7 @@
|
|||
* 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;
|
||||
package org.hibernate.userguide.mapping.basic.bitset;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.util.BitSet;
|
||||
|
@ -17,6 +17,7 @@ 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.userguide.mapping.basic.CustomBinaryJdbcType;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
|
@ -4,7 +4,7 @@
|
|||
* 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;
|
||||
package org.hibernate.userguide.mapping.basic.bitset;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.BitSet;
|
||||
|
@ -13,7 +13,7 @@ import org.hibernate.SharedSessionContract;
|
|||
import org.hibernate.type.descriptor.java.MutabilityPlan;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
* A BitSet's internal state is mutable, so handle that
|
||||
*/
|
||||
public class BitSetMutabilityPlan implements MutabilityPlan<BitSet> {
|
||||
/**
|
|
@ -1,4 +1,10 @@
|
|||
package org.hibernate.userguide.mapping.basic;
|
||||
/*
|
||||
* 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.bitset;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.PreparedStatement;
|
||||
|
@ -10,7 +16,6 @@ import java.util.Objects;
|
|||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.type.StringType;
|
||||
import org.hibernate.usertype.UserType;
|
||||
|
||||
import org.jboss.logging.Logger;
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* 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.mapping.basic;
|
||||
package org.hibernate.userguide.mapping.basic.bitset;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tests of various ways to map a basic value using `BitSet` as a case study.
|
||||
*
|
||||
* Used as the base for the Case Study section in the documentation
|
||||
*/
|
||||
package org.hibernate.userguide.mapping.basic.bitset;
|
|
@ -11,6 +11,7 @@ import java.lang.annotation.Retention;
|
|||
import jakarta.persistence.DiscriminatorColumn;
|
||||
import jakarta.persistence.DiscriminatorType;
|
||||
|
||||
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
@ -25,7 +26,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@java.lang.annotation.Target({METHOD, FIELD})
|
||||
@java.lang.annotation.Target({METHOD, FIELD, ANNOTATION_TYPE})
|
||||
@Retention( RUNTIME )
|
||||
public @interface AnyDiscriminator {
|
||||
/**
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.annotations;
|
|||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
@ -19,7 +20,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@java.lang.annotation.Target({METHOD, FIELD})
|
||||
@java.lang.annotation.Target({METHOD, FIELD, ANNOTATION_TYPE})
|
||||
@Retention( RUNTIME )
|
||||
@Repeatable(AnyDiscriminatorValues.class)
|
||||
public @interface AnyDiscriminatorValue {
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.annotations;
|
|||
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
@ -17,7 +18,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@java.lang.annotation.Target({METHOD, FIELD})
|
||||
@java.lang.annotation.Target({METHOD, FIELD, ANNOTATION_TYPE})
|
||||
@Retention( RUNTIME )
|
||||
public @interface AnyDiscriminatorValues {
|
||||
/**
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.annotations;
|
|||
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
@ -23,7 +24,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@java.lang.annotation.Target({METHOD, FIELD})
|
||||
@java.lang.annotation.Target({METHOD, FIELD, ANNOTATION_TYPE})
|
||||
@Retention( RUNTIME )
|
||||
public @interface AnyKeyJavaClass {
|
||||
/**
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.lang.annotation.Retention;
|
|||
|
||||
import org.hibernate.type.descriptor.java.BasicJavaTypeDescriptor;
|
||||
|
||||
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
@ -22,7 +23,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@java.lang.annotation.Target({METHOD, FIELD})
|
||||
@java.lang.annotation.Target({METHOD, FIELD,ANNOTATION_TYPE})
|
||||
@Retention( RUNTIME )
|
||||
public @interface AnyKeyJavaType {
|
||||
/**
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.lang.annotation.Retention;
|
|||
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
|
||||
|
||||
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
@ -22,7 +23,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@java.lang.annotation.Target({METHOD, FIELD})
|
||||
@java.lang.annotation.Target({METHOD, FIELD, ANNOTATION_TYPE})
|
||||
@Retention(RUNTIME)
|
||||
public @interface AnyKeyJdbcType {
|
||||
/**
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.annotations;
|
|||
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
@ -20,7 +21,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@java.lang.annotation.Target({METHOD, FIELD})
|
||||
@java.lang.annotation.Target({METHOD, FIELD, ANNOTATION_TYPE})
|
||||
@Retention(RUNTIME)
|
||||
public @interface AnyKeyJdbcTypeCode {
|
||||
/**
|
||||
|
|
|
@ -20,7 +20,16 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
/**
|
||||
* Registers the BasicJavaDescriptor to use for the given {@link #javaType}
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* Registrations applied to a package are processed before Hibernate begins to process
|
||||
* any attributes, etc.
|
||||
*
|
||||
* Registrations applied to a class are only applied once Hibernate begins to process
|
||||
* that class; it will also affect all future processing. However, it will not change
|
||||
* previous resolutions to use this newly registered one. Because of this randomness
|
||||
* it is recommended to only apply registrations to packages or to use a
|
||||
* {@link org.hibernate.boot.model.TypeContributor}.
|
||||
*
|
||||
* @see org.hibernate.boot.model.TypeContributor
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
|
|
|
@ -17,7 +17,8 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
/**
|
||||
* Grouping of {@link JavaTypeRegistration}
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* See notes on {@link JavaTypeRegistration} about using on packages
|
||||
* versus use on classes
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
|
|
|
@ -13,20 +13,27 @@ import java.lang.annotation.Retention;
|
|||
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
|
||||
|
||||
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
||||
import static java.lang.annotation.ElementType.PACKAGE;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* Describes a SqlTypeDescriptor to be added to the
|
||||
* {@link JdbcTypeDescriptorRegistry}
|
||||
* Describes a SqlTypeDescriptor to be added to the {@link JdbcTypeDescriptorRegistry}
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* Registrations applied to a package are processed before Hibernate begins to process
|
||||
* any attributes, etc.
|
||||
*
|
||||
* Registrations applied to a class are only applied once Hibernate begins to process
|
||||
* that class; it will also affect all future processing. However, it will not change
|
||||
* previous resolutions to use this newly registered one. Because of this randomness
|
||||
* it is recommended to only apply registrations to packages or to use a
|
||||
* {@link org.hibernate.boot.model.TypeContributor}.
|
||||
*
|
||||
* @see org.hibernate.boot.model.TypeContributor
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@java.lang.annotation.Target({PACKAGE, TYPE, ANNOTATION_TYPE})
|
||||
@java.lang.annotation.Target({PACKAGE, TYPE})
|
||||
@Inherited
|
||||
@Retention(RUNTIME)
|
||||
@Repeatable( JdbcTypeRegistrations.class )
|
||||
|
|
|
@ -9,7 +9,6 @@ package org.hibernate.annotations;
|
|||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
||||
import static java.lang.annotation.ElementType.PACKAGE;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
@ -17,11 +16,12 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
/**
|
||||
* Grouping of {@link JdbcTypeRegistration}
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* See notes on {@link JdbcTypeRegistration} about using on packages
|
||||
* versus use on classes
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@java.lang.annotation.Target({PACKAGE, TYPE, ANNOTATION_TYPE})
|
||||
@java.lang.annotation.Target({PACKAGE, TYPE})
|
||||
@Inherited
|
||||
@Retention(RUNTIME)
|
||||
public @interface JdbcTypeRegistrations {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
|
@ -14,6 +15,7 @@ import org.hibernate.type.descriptor.java.MutabilityPlan;
|
|||
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
|
@ -43,11 +45,14 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
* See <a href="package-summary.html#basic-value-mapping"/> for high-level discussion
|
||||
* of basic value mapping.
|
||||
*
|
||||
* @apiNote Valid on {@link ElementType#TYPE} in very limited cases - at the moment
|
||||
* it is only supported on an AttributeConverter implementation
|
||||
*
|
||||
* @see Immutable
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@java.lang.annotation.Target({METHOD, FIELD, ANNOTATION_TYPE})
|
||||
@java.lang.annotation.Target({METHOD, FIELD, ANNOTATION_TYPE, TYPE})
|
||||
@Inherited
|
||||
@Retention(RUNTIME)
|
||||
public @interface Mutability {
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.hibernate.annotations.MapKeyMutability;
|
|||
import org.hibernate.annotations.Mutability;
|
||||
import org.hibernate.annotations.Nationalized;
|
||||
import org.hibernate.annotations.Parameter;
|
||||
import org.hibernate.annotations.Target;
|
||||
import org.hibernate.annotations.common.reflection.XClass;
|
||||
import org.hibernate.annotations.common.reflection.XProperty;
|
||||
import org.hibernate.annotations.internal.NoJavaTypeDescriptor;
|
||||
|
@ -95,6 +96,8 @@ import jakarta.persistence.Temporal;
|
|||
import jakarta.persistence.TemporalType;
|
||||
import jakarta.persistence.Version;
|
||||
|
||||
import static org.hibernate.cfg.annotations.HCANNHelper.findAnnotation;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
* @author Emmanuel Bernard
|
||||
|
@ -391,7 +394,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
implicitJavaTypeAccess = (typeConfiguration) -> null;
|
||||
|
||||
explicitJavaTypeAccess = (typeConfiguration) -> {
|
||||
final CollectionIdJavaType javaTypeAnn = modelXProperty.getAnnotation( CollectionIdJavaType.class );
|
||||
final CollectionIdJavaType javaTypeAnn = findAnnotation( modelXProperty, CollectionIdJavaType.class );
|
||||
if ( javaTypeAnn != null ) {
|
||||
final Class<? extends BasicJavaTypeDescriptor<?>> javaType = normalizeJavaType( javaTypeAnn.value() );
|
||||
if ( javaType != null ) {
|
||||
|
@ -404,7 +407,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
};
|
||||
|
||||
explicitJdbcTypeAccess = (typeConfiguration) -> {
|
||||
final CollectionIdJdbcType jdbcTypeAnn = modelXProperty.getAnnotation( CollectionIdJdbcType.class );
|
||||
final CollectionIdJdbcType jdbcTypeAnn = findAnnotation( modelXProperty, CollectionIdJdbcType.class );
|
||||
if ( jdbcTypeAnn != null ) {
|
||||
final Class<? extends JdbcTypeDescriptor> jdbcType = normalizeJdbcType( jdbcTypeAnn.value() );
|
||||
if ( jdbcType != null ) {
|
||||
|
@ -413,7 +416,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
}
|
||||
}
|
||||
|
||||
final CollectionIdJdbcTypeCode jdbcTypeCodeAnn = modelXProperty.getAnnotation( CollectionIdJdbcTypeCode.class );
|
||||
final CollectionIdJdbcTypeCode jdbcTypeCodeAnn = findAnnotation( modelXProperty, CollectionIdJdbcTypeCode.class );
|
||||
if ( jdbcTypeCodeAnn != null ) {
|
||||
if ( jdbcTypeCodeAnn.value() != Integer.MIN_VALUE ) {
|
||||
return typeConfiguration.getJdbcTypeDescriptorRegistry().getDescriptor( jdbcTypeCodeAnn.value() );
|
||||
|
@ -424,12 +427,11 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
};
|
||||
|
||||
explicitMutabilityAccess = (typeConfiguration) -> {
|
||||
final CollectionIdMutability mutabilityAnn = modelXProperty.getAnnotation( CollectionIdMutability.class );
|
||||
final CollectionIdMutability mutabilityAnn = findAnnotation( modelXProperty, CollectionIdMutability.class );
|
||||
if ( mutabilityAnn != null ) {
|
||||
final Class<? extends MutabilityPlan<?>> mutability = normalizeMutability( mutabilityAnn.value() );
|
||||
if ( mutability != null ) {
|
||||
final ManagedBean<? extends MutabilityPlan<?>> jtdBean = beanRegistry
|
||||
.getBean( mutability );
|
||||
final ManagedBean<? extends MutabilityPlan<?>> jtdBean = beanRegistry.getBean( mutability );
|
||||
return jtdBean.getBeanInstance();
|
||||
}
|
||||
}
|
||||
|
@ -444,8 +446,14 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
}
|
||||
}
|
||||
|
||||
// if the value is converted, see if the converter Class is annotated `@Immutable`
|
||||
// if there is a converter, check it for mutability-related annotations
|
||||
if ( converterDescriptor != null ) {
|
||||
final Mutability converterMutabilityAnn = converterDescriptor.getAttributeConverterClass().getAnnotation( Mutability.class );
|
||||
if ( converterMutabilityAnn != null ) {
|
||||
final ManagedBean<? extends MutabilityPlan<?>> jtdBean = beanRegistry.getBean( converterMutabilityAnn.value() );
|
||||
return jtdBean.getBeanInstance();
|
||||
}
|
||||
|
||||
if ( converterDescriptor.getAttributeConverterClass().isAnnotationPresent( Immutable.class ) ) {
|
||||
return ImmutableMutabilityPlan.instance();
|
||||
}
|
||||
|
@ -495,7 +503,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
.getService( ManagedBeanRegistry.class );
|
||||
|
||||
explicitJdbcTypeAccess = typeConfiguration -> {
|
||||
final MapKeyJdbcType jdbcTypeAnn = mapAttribute.getAnnotation( MapKeyJdbcType.class );
|
||||
final MapKeyJdbcType jdbcTypeAnn = findAnnotation( mapAttribute, MapKeyJdbcType.class );
|
||||
if ( jdbcTypeAnn != null ) {
|
||||
final Class<? extends JdbcTypeDescriptor> jdbcTypeImpl = normalizeJdbcType( jdbcTypeAnn.value() );
|
||||
if ( jdbcTypeImpl != null ) {
|
||||
|
@ -504,7 +512,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
}
|
||||
}
|
||||
|
||||
final MapKeyJdbcTypeCode jdbcTypeCodeAnn = mapAttribute.getAnnotation( MapKeyJdbcTypeCode.class );
|
||||
final MapKeyJdbcTypeCode jdbcTypeCodeAnn = findAnnotation( mapAttribute, MapKeyJdbcTypeCode.class );
|
||||
if ( jdbcTypeCodeAnn != null ) {
|
||||
final int jdbcTypeCode = jdbcTypeCodeAnn.value();
|
||||
if ( jdbcTypeCode != Integer.MIN_VALUE ) {
|
||||
|
@ -516,7 +524,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
};
|
||||
|
||||
explicitJavaTypeAccess = typeConfiguration -> {
|
||||
final MapKeyJavaType javaTypeAnn = mapAttribute.getAnnotation( MapKeyJavaType.class );
|
||||
final MapKeyJavaType javaTypeAnn = findAnnotation( mapAttribute, MapKeyJavaType.class );
|
||||
if ( javaTypeAnn != null ) {
|
||||
final Class<? extends BasicJavaTypeDescriptor<?>> jdbcTypeImpl = normalizeJavaType( javaTypeAnn.value() );
|
||||
if ( jdbcTypeImpl != null ) {
|
||||
|
@ -534,7 +542,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
};
|
||||
|
||||
explicitMutabilityAccess = typeConfiguration -> {
|
||||
final MapKeyMutability mutabilityAnn = mapAttribute.getAnnotation( MapKeyMutability.class );
|
||||
final MapKeyMutability mutabilityAnn = findAnnotation( mapAttribute, MapKeyMutability.class );
|
||||
if ( mutabilityAnn != null ) {
|
||||
final Class<? extends MutabilityPlan<?>> mutability = normalizeMutability( mutabilityAnn.value() );
|
||||
if ( mutability != null ) {
|
||||
|
@ -555,6 +563,12 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
|
||||
// if the value is converted, see if the converter Class is annotated `@Immutable`
|
||||
if ( converterDescriptor != null ) {
|
||||
final Mutability converterMutabilityAnn = converterDescriptor.getAttributeConverterClass().getAnnotation( Mutability.class );
|
||||
if ( converterMutabilityAnn != null ) {
|
||||
final ManagedBean<? extends MutabilityPlan<?>> jtdBean = managedBeanRegistry.getBean( converterMutabilityAnn.value() );
|
||||
return jtdBean.getBeanInstance();
|
||||
}
|
||||
|
||||
if ( converterDescriptor.getAttributeConverterClass().isAnnotationPresent( Immutable.class ) ) {
|
||||
return ImmutableMutabilityPlan.instance();
|
||||
}
|
||||
|
@ -581,7 +595,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
.getService( ManagedBeanRegistry.class );
|
||||
|
||||
explicitJavaTypeAccess = (typeConfiguration) -> {
|
||||
final ListIndexJavaType javaTypeAnn = listAttribute.getAnnotation( ListIndexJavaType.class );
|
||||
final ListIndexJavaType javaTypeAnn = findAnnotation( listAttribute, ListIndexJavaType.class );
|
||||
if ( javaTypeAnn != null ) {
|
||||
final Class<? extends BasicJavaTypeDescriptor<?>> javaType = normalizeJavaType( javaTypeAnn.value() );
|
||||
if ( javaType != null ) {
|
||||
|
@ -594,7 +608,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
};
|
||||
|
||||
explicitJdbcTypeAccess = (typeConfiguration) -> {
|
||||
final ListIndexJdbcType jdbcTypeAnn = listAttribute.getAnnotation( ListIndexJdbcType.class );
|
||||
final ListIndexJdbcType jdbcTypeAnn = findAnnotation( listAttribute, ListIndexJdbcType.class );
|
||||
if ( jdbcTypeAnn != null ) {
|
||||
final Class<? extends JdbcTypeDescriptor> jdbcType = normalizeJdbcType( jdbcTypeAnn.value() );
|
||||
if ( jdbcType != null ) {
|
||||
|
@ -603,7 +617,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
}
|
||||
}
|
||||
|
||||
final ListIndexJdbcTypeCode jdbcTypeCodeAnn = listAttribute.getAnnotation( ListIndexJdbcTypeCode.class );
|
||||
final ListIndexJdbcTypeCode jdbcTypeCodeAnn = findAnnotation( listAttribute, ListIndexJdbcTypeCode.class );
|
||||
if ( jdbcTypeCodeAnn != null ) {
|
||||
return typeConfiguration.getJdbcTypeDescriptorRegistry().getDescriptor( jdbcTypeCodeAnn.value() );
|
||||
}
|
||||
|
@ -736,7 +750,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
}
|
||||
|
||||
private void prepareAnyDiscriminator(XProperty modelXProperty) {
|
||||
final AnyDiscriminator anyDiscriminatorAnn = modelXProperty.getAnnotation( AnyDiscriminator.class );
|
||||
final AnyDiscriminator anyDiscriminatorAnn = findAnnotation( modelXProperty, AnyDiscriminator.class );
|
||||
|
||||
implicitJavaTypeAccess = (typeConfiguration) -> {
|
||||
if ( anyDiscriminatorAnn != null ) {
|
||||
|
@ -783,7 +797,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
.getService( ManagedBeanRegistry.class );
|
||||
|
||||
explicitJavaTypeAccess = (typeConfiguration) -> {
|
||||
final AnyKeyJavaType javaTypeAnn = modelXProperty.getAnnotation( AnyKeyJavaType.class );
|
||||
final AnyKeyJavaType javaTypeAnn = findAnnotation( modelXProperty, AnyKeyJavaType.class );
|
||||
if ( javaTypeAnn != null ) {
|
||||
final Class<? extends BasicJavaTypeDescriptor<?>> javaType = normalizeJavaType( javaTypeAnn.value() );
|
||||
|
||||
|
@ -793,7 +807,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
}
|
||||
}
|
||||
|
||||
final AnyKeyJavaClass javaClassAnn = modelXProperty.getAnnotation( AnyKeyJavaClass.class );
|
||||
final AnyKeyJavaClass javaClassAnn = findAnnotation( modelXProperty, AnyKeyJavaClass.class );
|
||||
if ( javaClassAnn != null ) {
|
||||
//noinspection rawtypes
|
||||
return (BasicJavaTypeDescriptor) typeConfiguration
|
||||
|
@ -805,7 +819,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
};
|
||||
|
||||
explicitJdbcTypeAccess = (typeConfiguration) -> {
|
||||
final AnyKeyJdbcType jdbcTypeAnn = modelXProperty.getAnnotation( AnyKeyJdbcType.class );
|
||||
final AnyKeyJdbcType jdbcTypeAnn = findAnnotation( modelXProperty, AnyKeyJdbcType.class );
|
||||
if ( jdbcTypeAnn != null ) {
|
||||
final Class<? extends JdbcTypeDescriptor> jdbcType = normalizeJdbcType( jdbcTypeAnn.value() );
|
||||
if ( jdbcType != null ) {
|
||||
|
@ -814,7 +828,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
}
|
||||
}
|
||||
|
||||
final AnyKeyJdbcTypeCode jdbcTypeCodeAnn = modelXProperty.getAnnotation( AnyKeyJdbcTypeCode.class );
|
||||
final AnyKeyJdbcTypeCode jdbcTypeCodeAnn = findAnnotation( modelXProperty, AnyKeyJdbcTypeCode.class );
|
||||
if ( jdbcTypeCodeAnn != null ) {
|
||||
if ( jdbcTypeCodeAnn.value() != Integer.MIN_VALUE ) {
|
||||
return typeConfiguration.getJdbcTypeDescriptorRegistry().getDescriptor( jdbcTypeCodeAnn.value() );
|
||||
|
@ -833,7 +847,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
.getServiceRegistry()
|
||||
.getService( ManagedBeanRegistry.class );
|
||||
|
||||
final JdbcType jdbcTypeAnn = attributeXProperty.getAnnotation( JdbcType.class );
|
||||
final JdbcType jdbcTypeAnn = findAnnotation( attributeXProperty, JdbcType.class );
|
||||
if ( jdbcTypeAnn != null ) {
|
||||
final Class<? extends JdbcTypeDescriptor> jdbcType = normalizeJdbcType( jdbcTypeAnn.value() );
|
||||
if ( jdbcType != null ) {
|
||||
|
@ -842,7 +856,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
}
|
||||
}
|
||||
|
||||
final JdbcTypeCode jdbcTypeCodeAnn = attributeXProperty.getAnnotation( JdbcTypeCode.class );
|
||||
final JdbcTypeCode jdbcTypeCodeAnn = findAnnotation( attributeXProperty, JdbcTypeCode.class );
|
||||
if ( jdbcTypeCodeAnn != null ) {
|
||||
final int jdbcTypeCode = jdbcTypeCodeAnn.value();
|
||||
if ( jdbcTypeCode != Integer.MIN_VALUE ) {
|
||||
|
@ -862,7 +876,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
.getService( ManagedBeanRegistry.class );
|
||||
|
||||
explicitMutabilityAccess = typeConfiguration -> {
|
||||
final Mutability mutabilityAnn = attributeXProperty.getAnnotation( Mutability.class );
|
||||
final Mutability mutabilityAnn = findAnnotation( attributeXProperty, Mutability.class );
|
||||
if ( mutabilityAnn != null ) {
|
||||
final Class<? extends MutabilityPlan<?>> mutability = normalizeMutability( mutabilityAnn.value() );
|
||||
if ( mutability != null ) {
|
||||
|
@ -888,6 +902,12 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
|
||||
// if the value is converted, see if the converter Class is annotated `@Immutable`
|
||||
if ( converterDescriptor != null ) {
|
||||
final Mutability converterMutabilityAnn = converterDescriptor.getAttributeConverterClass().getAnnotation( Mutability.class );
|
||||
if ( converterMutabilityAnn != null ) {
|
||||
final ManagedBean<? extends MutabilityPlan<?>> jtdBean = managedBeanRegistry.getBean( converterMutabilityAnn.value() );
|
||||
return jtdBean.getBeanInstance();
|
||||
}
|
||||
|
||||
if ( converterDescriptor.getAttributeConverterClass().isAnnotationPresent( Immutable.class ) ) {
|
||||
return ImmutableMutabilityPlan.instance();
|
||||
}
|
||||
|
@ -913,7 +933,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
.getService( ManagedBeanRegistry.class );
|
||||
|
||||
explicitJavaTypeAccess = typeConfiguration -> {
|
||||
final JavaType javaTypeAnn = attributeXProperty.getAnnotation( JavaType.class );
|
||||
final JavaType javaTypeAnn = findAnnotation( attributeXProperty, JavaType.class );
|
||||
if ( javaTypeAnn != null ) {
|
||||
final Class<? extends BasicJavaTypeDescriptor<?>> javaType = normalizeJavaType( javaTypeAnn.value() );
|
||||
|
||||
|
@ -923,6 +943,13 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
}
|
||||
}
|
||||
|
||||
final Target targetAnn = findAnnotation( attributeXProperty, Target.class );
|
||||
if ( targetAnn != null ) {
|
||||
return (BasicJavaTypeDescriptor) typeConfiguration
|
||||
.getJavaTypeDescriptorRegistry()
|
||||
.getDescriptor( targetAnn.value() );
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
|
@ -1095,10 +1122,6 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
basicValue.setTemporalPrecision( temporalPrecision );
|
||||
}
|
||||
|
||||
// todo (6.0) : explicit SqlTypeDescriptor / JDBC type-code
|
||||
// todo (6.0) : explicit mutability / immutable
|
||||
// todo (6.0) : explicit Comparator
|
||||
|
||||
linkWithValue();
|
||||
|
||||
boolean isInSecondPass = buildingContext.getMetadataCollector().isInSecondPass();
|
||||
|
@ -1285,7 +1308,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
|
||||
@Override
|
||||
public Class<? extends UserType<?>> customType(XProperty xProperty) {
|
||||
final CustomType customType = xProperty.getAnnotation( CustomType.class );
|
||||
final CustomType customType = findAnnotation( xProperty, CustomType.class );
|
||||
if ( customType == null ) {
|
||||
return null;
|
||||
}
|
||||
|
@ -1295,7 +1318,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
|
||||
@Override
|
||||
public Parameter[] customTypeParameters(XProperty xProperty) {
|
||||
final CustomType customType = xProperty.getAnnotation( CustomType.class );
|
||||
final CustomType customType = findAnnotation( xProperty, CustomType.class );
|
||||
if ( customType == null ) {
|
||||
return null;
|
||||
}
|
||||
|
@ -1340,7 +1363,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
|
||||
@Override
|
||||
public Class<? extends UserType<?>> customType(XProperty xProperty) {
|
||||
final MapKeyCustomType customType = xProperty.getAnnotation( MapKeyCustomType.class );
|
||||
final MapKeyCustomType customType = findAnnotation( xProperty, MapKeyCustomType.class );
|
||||
if ( customType == null ) {
|
||||
return null;
|
||||
}
|
||||
|
@ -1350,7 +1373,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
|
||||
@Override
|
||||
public Parameter[] customTypeParameters(XProperty xProperty) {
|
||||
final MapKeyCustomType customType = xProperty.getAnnotation( MapKeyCustomType.class );
|
||||
final MapKeyCustomType customType = findAnnotation( xProperty, MapKeyCustomType.class );
|
||||
if ( customType == null ) {
|
||||
return null;
|
||||
}
|
||||
|
@ -1363,7 +1386,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
|
||||
@Override
|
||||
public Class<? extends UserType<?>> customType(XProperty xProperty) {
|
||||
final CollectionIdCustomType customType = xProperty.getAnnotation( CollectionIdCustomType.class );
|
||||
final CollectionIdCustomType customType = findAnnotation( xProperty, CollectionIdCustomType.class );
|
||||
if ( customType == null ) {
|
||||
return null;
|
||||
}
|
||||
|
@ -1373,7 +1396,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
|||
|
||||
@Override
|
||||
public Parameter[] customTypeParameters(XProperty xProperty) {
|
||||
final CollectionIdCustomType customType = xProperty.getAnnotation( CollectionIdCustomType.class );
|
||||
final CollectionIdCustomType customType = findAnnotation( xProperty, CollectionIdCustomType.class );
|
||||
if ( customType == null ) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -6,8 +6,11 @@
|
|||
*/
|
||||
package org.hibernate.cfg.annotations;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Member;
|
||||
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.annotations.common.reflection.XAnnotatedElement;
|
||||
import org.hibernate.annotations.common.reflection.XProperty;
|
||||
import org.hibernate.annotations.common.reflection.java.JavaXMember;
|
||||
|
||||
|
@ -16,6 +19,7 @@ import org.hibernate.annotations.common.reflection.java.JavaXMember;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Internal
|
||||
public final class HCANNHelper {
|
||||
|
||||
/**
|
||||
|
@ -47,4 +51,35 @@ public final class HCANNHelper {
|
|||
public static Member getUnderlyingMember(final JavaXMember jxProperty) {
|
||||
return jxProperty.getMember();
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate an annotation on an annotated member, allowing for composed annotations (meta-annotations).
|
||||
*
|
||||
* @implNote Searches only one level deep
|
||||
*/
|
||||
static <T extends Annotation> T findAnnotation(XAnnotatedElement xAnnotatedElement, Class<T> annotationType) {
|
||||
// first, see if we can find it directly...
|
||||
final T direct = xAnnotatedElement.getAnnotation( annotationType );
|
||||
if ( direct != null ) {
|
||||
return direct;
|
||||
}
|
||||
|
||||
// or as composed...
|
||||
for ( int i = 0; i < xAnnotatedElement.getAnnotations().length; i++ ) {
|
||||
final Annotation annotation = xAnnotatedElement.getAnnotations()[ i ];
|
||||
if ( annotationType.equals( annotation.getClass() ) ) {
|
||||
// we would have found this on the direct search, so no need
|
||||
// to check its meta-annotations
|
||||
continue;
|
||||
}
|
||||
|
||||
// we only check one level deep
|
||||
final T metaAnn = annotation.annotationType().getAnnotation( annotationType );
|
||||
if ( metaAnn != null ) {
|
||||
return metaAnn;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.any.annotations;
|
||||
|
||||
import org.hibernate.annotations.Any;
|
||||
|
||||
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 jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
@DomainModel( annotatedClasses = {
|
||||
ComposedAnyDiscriminatorMappingsTests.EntityWithComposedAnyDiscriminatorMappings.class,
|
||||
CharProperty.class,
|
||||
StringProperty.class,
|
||||
IntegerProperty.class
|
||||
} )
|
||||
@SessionFactory
|
||||
public class ComposedAnyDiscriminatorMappingsTests {
|
||||
@Test
|
||||
public void testUsage(SessionFactoryScope scope) {
|
||||
// atm this will blow up because the mapping will fail
|
||||
scope.inTransaction( (session) -> {
|
||||
session.createQuery( "select s from StringProperty s" ).list();
|
||||
session.createQuery( "select ph from PropertyHolder ph" ).list();
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity( name = "PropertyHolder" )
|
||||
@Table( name = "t_any_discrim_composed" )
|
||||
public static class EntityWithComposedAnyDiscriminatorMappings {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
@Any
|
||||
@Column(name = "property_type")
|
||||
@JoinColumn(name = "property_id")
|
||||
@PropertyDiscriminatorMapping
|
||||
private Property property;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.orm.test.any.annotations;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
import org.hibernate.annotations.AnyDiscriminator;
|
||||
import org.hibernate.annotations.AnyDiscriminatorValue;
|
||||
import org.hibernate.annotations.AnyKeyJavaClass;
|
||||
|
||||
import jakarta.persistence.DiscriminatorType;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
|
||||
@java.lang.annotation.Target({METHOD, FIELD})
|
||||
@Retention( RUNTIME )
|
||||
|
||||
// this is the default behavior anyway, but let's check that it is found
|
||||
@AnyDiscriminator( DiscriminatorType.STRING )
|
||||
|
||||
@AnyKeyJavaClass( Integer.class )
|
||||
|
||||
@AnyDiscriminatorValue( discriminator = "S", entity = StringProperty.class )
|
||||
@AnyDiscriminatorValue( discriminator = "I", entity = IntegerProperty.class )
|
||||
public @interface PropertyDiscriminatorMapping {
|
||||
}
|
|
@ -25,7 +25,6 @@ import org.hibernate.testing.orm.junit.Setting;
|
|||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static com.ibm.icu.impl.ValidIdentifiers.Datatype.u;
|
||||
import static org.hibernate.cfg.AvailableSettings.GENERATE_STATISTICS;
|
||||
import static org.hibernate.cfg.AvailableSettings.USE_QUERY_CACHE;
|
||||
import static org.hibernate.cfg.AvailableSettings.USE_SECOND_LEVEL_CACHE;
|
||||
|
@ -34,7 +33,6 @@ import static org.junit.Assert.assertFalse;
|
|||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
|
@ -353,7 +351,7 @@ public class MutableNaturalIdTest {
|
|||
.using( "name", "steve" )
|
||||
.using( "org", "hb" )
|
||||
.load();
|
||||
assertNotNull( u );
|
||||
assertNotNull( beforeEvict );
|
||||
assertEquals( statistics.getPrepareStatementCount(), 1 );
|
||||
|
||||
session.evict( beforeEvict );
|
||||
|
|
|
@ -14,6 +14,7 @@ import java.lang.annotation.Target;
|
|||
|
||||
import jakarta.persistence.SharedCacheMode;
|
||||
|
||||
import org.hibernate.boot.model.TypeContributor;
|
||||
import org.hibernate.cache.spi.access.AccessType;
|
||||
|
||||
import org.hibernate.testing.orm.domain.DomainModelDescriptor;
|
||||
|
@ -108,6 +109,8 @@ public @interface DomainModel {
|
|||
|
||||
AccessType accessType() default AccessType.READ_WRITE;
|
||||
|
||||
Class<? extends TypeContributor>[] typeContributors() default {};
|
||||
|
||||
@interface ExtraQueryImport {
|
||||
String name();
|
||||
Class<?> importedClass();
|
||||
|
|
|
@ -14,14 +14,16 @@ import java.util.Optional;
|
|||
|
||||
import org.hibernate.boot.Metadata;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.internal.MetadataBuilderImpl;
|
||||
import org.hibernate.boot.model.TypeContributor;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.internal.util.JavaHelper;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.RootClass;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
|
||||
import org.hibernate.type.BlobType;
|
||||
import org.hibernate.type.ClobType;
|
||||
import org.hibernate.type.NClobType;
|
||||
|
@ -88,6 +90,7 @@ public class DomainModelExtension
|
|||
final DomainModel domainModelAnnotation = domainModelAnnotationWrapper.get();
|
||||
|
||||
final MetadataSources metadataSources = new MetadataSources( serviceRegistry );
|
||||
final ManagedBeanRegistry managedBeanRegistry = serviceRegistry.getService( ManagedBeanRegistry.class );
|
||||
|
||||
for ( String annotatedPackageName : domainModelAnnotation.annotatedPackageNames() ) {
|
||||
metadataSources.addPackage( annotatedPackageName );
|
||||
|
@ -127,12 +130,20 @@ public class DomainModelExtension
|
|||
metadataSources.addQueryImport( importedClass.getSimpleName(), importedClass );
|
||||
}
|
||||
|
||||
MetadataImplementor metadataImplementor = (MetadataImplementor) metadataSources.buildMetadata();
|
||||
final MetadataBuilderImpl metadataBuilder = (MetadataBuilderImpl) metadataSources.getMetadataBuilder();
|
||||
|
||||
for ( Class<? extends TypeContributor> contributorType : domainModelAnnotation.typeContributors() ) {
|
||||
final TypeContributor contributor = managedBeanRegistry.getBean( contributorType ).getBeanInstance();
|
||||
contributor.contribute( metadataBuilder, serviceRegistry );
|
||||
}
|
||||
|
||||
MetadataImplementor metadataImplementor = metadataBuilder.build();
|
||||
applyCacheSettings(
|
||||
metadataImplementor,
|
||||
domainModelAnnotation.overrideCacheStrategy(),
|
||||
domainModelAnnotation.concurrencyStrategy()
|
||||
);
|
||||
|
||||
return metadataImplementor;
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue