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]
|
[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]
|
[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]
|
[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`
|
or using the `MetadataBuilder`
|
||||||
|
@ -245,7 +245,7 @@ With the new `BitSetType` being registered as `bitset`, the entity mapping looks
|
||||||
====
|
====
|
||||||
[source, JAVA, indent=0]
|
[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]
|
[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]
|
[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]
|
[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).
|
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 map such an association, Hibernate needs to understand 3 things:
|
||||||
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.
|
|
||||||
|
|
||||||
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]]
|
[[associations-any-property-example]]
|
||||||
.`Property` class hierarchy
|
.`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]]
|
[[associations-any-example]]
|
||||||
.`@Any` mapping usage
|
.`@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`.
|
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,
|
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.
|
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.
|
To see the `@Any` annotation in action, consider the next examples.
|
||||||
|
|
||||||
If we persist an `IntegerProperty` as well as a `StringProperty` entity, and associate
|
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]]
|
[[associations-many-to-any]]
|
||||||
===== `@ManyToAny` mapping
|
===== `@ManyToAny` mapping
|
||||||
|
|
||||||
While the `@Any` mapping is useful to emulate a `@ManyToOne` association when there can be multiple target entities,
|
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.
|
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.
|
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.
|
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]]
|
[[associations-JoinFormula]]
|
||||||
==== `@JoinFormula` mapping
|
==== `@JoinFormula` mapping
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ Generally, the `@Basic` annotation can be ignored as it is assumed by default.
|
||||||
examples are ultimately the same.
|
examples are ultimately the same.
|
||||||
|
|
||||||
[[basic-annotation-explicit-example]]
|
[[basic-annotation-explicit-example]]
|
||||||
.`@Basic` declared explicitly
|
.`@Basic` explicit
|
||||||
====
|
====
|
||||||
[source, JAVA, indent=0]
|
[source, JAVA, indent=0]
|
||||||
----
|
----
|
||||||
|
@ -163,7 +163,7 @@ include::{extrasdir}/basic/mapping-column-formula-persistence-example.sql[]
|
||||||
|
|
||||||
[NOTE]
|
[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
|
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
|
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.
|
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]]
|
[[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.jpa.boot.internal.PersistenceUnitInfoDescriptor;
|
||||||
import org.hibernate.service.ServiceRegistry;
|
import org.hibernate.service.ServiceRegistry;
|
||||||
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
|
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
|
||||||
import org.hibernate.userguide.mapping.basic.BitSetUserType;
|
import org.hibernate.userguide.mapping.basic.bitset.BitSetUserType;
|
||||||
|
|
||||||
import org.junit.Test;
|
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
|
* 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
|
* 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.sql.Types;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
|
@ -14,10 +14,10 @@ import jakarta.persistence.Converter;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
|
import org.assertj.core.api.Assertions;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.metamodel.MappingMetamodel;
|
import org.hibernate.metamodel.MappingMetamodel;
|
||||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
|
||||||
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
|
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
|
||||||
import org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter;
|
import org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
@ -33,7 +33,7 @@ import static org.hamcrest.Matchers.instanceOf;
|
||||||
import static org.hamcrest.Matchers.isOneOf;
|
import static org.hamcrest.Matchers.isOneOf;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* Test using a converter to map the BitSet
|
||||||
*/
|
*/
|
||||||
@DomainModel( annotatedClasses = BitSetConverterTests.Product.class )
|
@DomainModel( annotatedClasses = BitSetConverterTests.Product.class )
|
||||||
@SessionFactory
|
@SessionFactory
|
||||||
|
@ -53,6 +53,8 @@ public class BitSetConverterTests {
|
||||||
final JpaAttributeConverter converter = (JpaAttributeConverter) attributeMapping.getValueConverter();
|
final JpaAttributeConverter converter = (JpaAttributeConverter) attributeMapping.getValueConverter();
|
||||||
assertThat( converter.getConverterBean().getBeanClass(), equalTo( BitSetConverter.class ) );
|
assertThat( converter.getConverterBean().getBeanClass(), equalTo( BitSetConverter.class ) );
|
||||||
|
|
||||||
|
Assertions.assertThat( attributeMapping.getExposedMutabilityPlan() ).isNotInstanceOf( BitSetMutabilityPlan.class );
|
||||||
|
|
||||||
assertThat(
|
assertThat(
|
||||||
attributeMapping.getJdbcMapping().getJdbcTypeDescriptor().getJdbcTypeCode(),
|
attributeMapping.getJdbcMapping().getJdbcTypeDescriptor().getJdbcTypeCode(),
|
||||||
isOneOf( Types.VARCHAR, Types.NVARCHAR )
|
isOneOf( Types.VARCHAR, Types.NVARCHAR )
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
* 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
|
* 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 java.util.BitSet;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
* 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
|
* 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.sql.Types;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
|
@ -15,7 +15,6 @@ import jakarta.persistence.Table;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.metamodel.MappingMetamodel;
|
import org.hibernate.metamodel.MappingMetamodel;
|
||||||
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
|
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
|
||||||
import org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter;
|
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
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.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.hamcrest.Matchers;
|
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.isOneOf;
|
|
||||||
import static org.hamcrest.Matchers.nullValue;
|
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.sql.Types;
|
||||||
import java.util.BitSet;
|
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
|
* 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
|
* 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 java.util.BitSet;
|
||||||
import jakarta.persistence.Basic;
|
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
|
@ -4,10 +4,10 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
* 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
|
* 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 java.util.BitSet;
|
||||||
import jakarta.persistence.Basic;
|
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
* 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
|
* 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.sql.Types;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
* 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
|
* 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.sql.Types;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
|
@ -14,6 +14,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.metamodel.MappingMetamodel;
|
import org.hibernate.metamodel.MappingMetamodel;
|
||||||
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
|
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
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.DomainModel;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
* 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
|
* 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.sql.Types;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
|
@ -17,6 +17,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.metamodel.MappingMetamodel;
|
import org.hibernate.metamodel.MappingMetamodel;
|
||||||
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
|
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
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.DomainModel;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
* 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
|
* 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.io.Serializable;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
|
@ -13,7 +13,7 @@ import org.hibernate.SharedSessionContract;
|
||||||
import org.hibernate.type.descriptor.java.MutabilityPlan;
|
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> {
|
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.io.Serializable;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
|
@ -10,7 +16,6 @@ import java.util.Objects;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.type.StringType;
|
|
||||||
import org.hibernate.usertype.UserType;
|
import org.hibernate.usertype.UserType;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* 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 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.DiscriminatorColumn;
|
||||||
import jakarta.persistence.DiscriminatorType;
|
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.FIELD;
|
||||||
import static java.lang.annotation.ElementType.METHOD;
|
import static java.lang.annotation.ElementType.METHOD;
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
@ -25,7 +26,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
*
|
*
|
||||||
* @since 6.0
|
* @since 6.0
|
||||||
*/
|
*/
|
||||||
@java.lang.annotation.Target({METHOD, FIELD})
|
@java.lang.annotation.Target({METHOD, FIELD, ANNOTATION_TYPE})
|
||||||
@Retention( RUNTIME )
|
@Retention( RUNTIME )
|
||||||
public @interface AnyDiscriminator {
|
public @interface AnyDiscriminator {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.annotations;
|
||||||
import java.lang.annotation.Repeatable;
|
import java.lang.annotation.Repeatable;
|
||||||
import java.lang.annotation.Retention;
|
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.FIELD;
|
||||||
import static java.lang.annotation.ElementType.METHOD;
|
import static java.lang.annotation.ElementType.METHOD;
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
@ -19,7 +20,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
*
|
*
|
||||||
* @since 6.0
|
* @since 6.0
|
||||||
*/
|
*/
|
||||||
@java.lang.annotation.Target({METHOD, FIELD})
|
@java.lang.annotation.Target({METHOD, FIELD, ANNOTATION_TYPE})
|
||||||
@Retention( RUNTIME )
|
@Retention( RUNTIME )
|
||||||
@Repeatable(AnyDiscriminatorValues.class)
|
@Repeatable(AnyDiscriminatorValues.class)
|
||||||
public @interface AnyDiscriminatorValue {
|
public @interface AnyDiscriminatorValue {
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.annotations;
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
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.FIELD;
|
||||||
import static java.lang.annotation.ElementType.METHOD;
|
import static java.lang.annotation.ElementType.METHOD;
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
@ -17,7 +18,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
*
|
*
|
||||||
* @since 6.0
|
* @since 6.0
|
||||||
*/
|
*/
|
||||||
@java.lang.annotation.Target({METHOD, FIELD})
|
@java.lang.annotation.Target({METHOD, FIELD, ANNOTATION_TYPE})
|
||||||
@Retention( RUNTIME )
|
@Retention( RUNTIME )
|
||||||
public @interface AnyDiscriminatorValues {
|
public @interface AnyDiscriminatorValues {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.annotations;
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
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.FIELD;
|
||||||
import static java.lang.annotation.ElementType.METHOD;
|
import static java.lang.annotation.ElementType.METHOD;
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
@ -23,7 +24,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
*
|
*
|
||||||
* @since 6.0
|
* @since 6.0
|
||||||
*/
|
*/
|
||||||
@java.lang.annotation.Target({METHOD, FIELD})
|
@java.lang.annotation.Target({METHOD, FIELD, ANNOTATION_TYPE})
|
||||||
@Retention( RUNTIME )
|
@Retention( RUNTIME )
|
||||||
public @interface AnyKeyJavaClass {
|
public @interface AnyKeyJavaClass {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,6 +10,7 @@ import java.lang.annotation.Retention;
|
||||||
|
|
||||||
import org.hibernate.type.descriptor.java.BasicJavaTypeDescriptor;
|
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.FIELD;
|
||||||
import static java.lang.annotation.ElementType.METHOD;
|
import static java.lang.annotation.ElementType.METHOD;
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
@ -22,7 +23,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
*
|
*
|
||||||
* @since 6.0
|
* @since 6.0
|
||||||
*/
|
*/
|
||||||
@java.lang.annotation.Target({METHOD, FIELD})
|
@java.lang.annotation.Target({METHOD, FIELD,ANNOTATION_TYPE})
|
||||||
@Retention( RUNTIME )
|
@Retention( RUNTIME )
|
||||||
public @interface AnyKeyJavaType {
|
public @interface AnyKeyJavaType {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,6 +10,7 @@ import java.lang.annotation.Retention;
|
||||||
|
|
||||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
|
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.FIELD;
|
||||||
import static java.lang.annotation.ElementType.METHOD;
|
import static java.lang.annotation.ElementType.METHOD;
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
@ -22,7 +23,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
*
|
*
|
||||||
* @since 6.0
|
* @since 6.0
|
||||||
*/
|
*/
|
||||||
@java.lang.annotation.Target({METHOD, FIELD})
|
@java.lang.annotation.Target({METHOD, FIELD, ANNOTATION_TYPE})
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
public @interface AnyKeyJdbcType {
|
public @interface AnyKeyJdbcType {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.annotations;
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
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.FIELD;
|
||||||
import static java.lang.annotation.ElementType.METHOD;
|
import static java.lang.annotation.ElementType.METHOD;
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
@ -20,7 +21,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
*
|
*
|
||||||
* @since 6.0
|
* @since 6.0
|
||||||
*/
|
*/
|
||||||
@java.lang.annotation.Target({METHOD, FIELD})
|
@java.lang.annotation.Target({METHOD, FIELD, ANNOTATION_TYPE})
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
public @interface AnyKeyJdbcTypeCode {
|
public @interface AnyKeyJdbcTypeCode {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,7 +20,16 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
/**
|
/**
|
||||||
* Registers the BasicJavaDescriptor to use for the given {@link #javaType}
|
* 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
|
* @since 6.0
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -17,7 +17,8 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
/**
|
/**
|
||||||
* Grouping of {@link JavaTypeRegistration}
|
* Grouping of {@link JavaTypeRegistration}
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* See notes on {@link JavaTypeRegistration} about using on packages
|
||||||
|
* versus use on classes
|
||||||
*
|
*
|
||||||
* @since 6.0
|
* @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.JdbcTypeDescriptor;
|
||||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
|
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.PACKAGE;
|
||||||
import static java.lang.annotation.ElementType.TYPE;
|
import static java.lang.annotation.ElementType.TYPE;
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes a SqlTypeDescriptor to be added to the
|
* Describes a SqlTypeDescriptor to be added to the {@link JdbcTypeDescriptorRegistry}
|
||||||
* {@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
|
* @since 6.0
|
||||||
*/
|
*/
|
||||||
@java.lang.annotation.Target({PACKAGE, TYPE, ANNOTATION_TYPE})
|
@java.lang.annotation.Target({PACKAGE, TYPE})
|
||||||
@Inherited
|
@Inherited
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
@Repeatable( JdbcTypeRegistrations.class )
|
@Repeatable( JdbcTypeRegistrations.class )
|
||||||
|
|
|
@ -9,7 +9,6 @@ package org.hibernate.annotations;
|
||||||
import java.lang.annotation.Inherited;
|
import java.lang.annotation.Inherited;
|
||||||
import java.lang.annotation.Retention;
|
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.PACKAGE;
|
||||||
import static java.lang.annotation.ElementType.TYPE;
|
import static java.lang.annotation.ElementType.TYPE;
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
@ -17,11 +16,12 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
/**
|
/**
|
||||||
* Grouping of {@link JdbcTypeRegistration}
|
* Grouping of {@link JdbcTypeRegistration}
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* See notes on {@link JdbcTypeRegistration} about using on packages
|
||||||
|
* versus use on classes
|
||||||
*
|
*
|
||||||
* @since 6.0
|
* @since 6.0
|
||||||
*/
|
*/
|
||||||
@java.lang.annotation.Target({PACKAGE, TYPE, ANNOTATION_TYPE})
|
@java.lang.annotation.Target({PACKAGE, TYPE})
|
||||||
@Inherited
|
@Inherited
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
public @interface JdbcTypeRegistrations {
|
public @interface JdbcTypeRegistrations {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.annotations;
|
package org.hibernate.annotations;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Inherited;
|
import java.lang.annotation.Inherited;
|
||||||
import java.lang.annotation.Retention;
|
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.ANNOTATION_TYPE;
|
||||||
import static java.lang.annotation.ElementType.FIELD;
|
import static java.lang.annotation.ElementType.FIELD;
|
||||||
import static java.lang.annotation.ElementType.METHOD;
|
import static java.lang.annotation.ElementType.METHOD;
|
||||||
|
import static java.lang.annotation.ElementType.TYPE;
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
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
|
* See <a href="package-summary.html#basic-value-mapping"/> for high-level discussion
|
||||||
* of basic value mapping.
|
* 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
|
* @see Immutable
|
||||||
*
|
*
|
||||||
* @since 6.0
|
* @since 6.0
|
||||||
*/
|
*/
|
||||||
@java.lang.annotation.Target({METHOD, FIELD, ANNOTATION_TYPE})
|
@java.lang.annotation.Target({METHOD, FIELD, ANNOTATION_TYPE, TYPE})
|
||||||
@Inherited
|
@Inherited
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
public @interface Mutability {
|
public @interface Mutability {
|
||||||
|
|
|
@ -44,6 +44,7 @@ import org.hibernate.annotations.MapKeyMutability;
|
||||||
import org.hibernate.annotations.Mutability;
|
import org.hibernate.annotations.Mutability;
|
||||||
import org.hibernate.annotations.Nationalized;
|
import org.hibernate.annotations.Nationalized;
|
||||||
import org.hibernate.annotations.Parameter;
|
import org.hibernate.annotations.Parameter;
|
||||||
|
import org.hibernate.annotations.Target;
|
||||||
import org.hibernate.annotations.common.reflection.XClass;
|
import org.hibernate.annotations.common.reflection.XClass;
|
||||||
import org.hibernate.annotations.common.reflection.XProperty;
|
import org.hibernate.annotations.common.reflection.XProperty;
|
||||||
import org.hibernate.annotations.internal.NoJavaTypeDescriptor;
|
import org.hibernate.annotations.internal.NoJavaTypeDescriptor;
|
||||||
|
@ -95,6 +96,8 @@ import jakarta.persistence.Temporal;
|
||||||
import jakarta.persistence.TemporalType;
|
import jakarta.persistence.TemporalType;
|
||||||
import jakarta.persistence.Version;
|
import jakarta.persistence.Version;
|
||||||
|
|
||||||
|
import static org.hibernate.cfg.annotations.HCANNHelper.findAnnotation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
* @author Emmanuel Bernard
|
* @author Emmanuel Bernard
|
||||||
|
@ -391,7 +394,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
||||||
implicitJavaTypeAccess = (typeConfiguration) -> null;
|
implicitJavaTypeAccess = (typeConfiguration) -> null;
|
||||||
|
|
||||||
explicitJavaTypeAccess = (typeConfiguration) -> {
|
explicitJavaTypeAccess = (typeConfiguration) -> {
|
||||||
final CollectionIdJavaType javaTypeAnn = modelXProperty.getAnnotation( CollectionIdJavaType.class );
|
final CollectionIdJavaType javaTypeAnn = findAnnotation( modelXProperty, CollectionIdJavaType.class );
|
||||||
if ( javaTypeAnn != null ) {
|
if ( javaTypeAnn != null ) {
|
||||||
final Class<? extends BasicJavaTypeDescriptor<?>> javaType = normalizeJavaType( javaTypeAnn.value() );
|
final Class<? extends BasicJavaTypeDescriptor<?>> javaType = normalizeJavaType( javaTypeAnn.value() );
|
||||||
if ( javaType != null ) {
|
if ( javaType != null ) {
|
||||||
|
@ -404,7 +407,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
||||||
};
|
};
|
||||||
|
|
||||||
explicitJdbcTypeAccess = (typeConfiguration) -> {
|
explicitJdbcTypeAccess = (typeConfiguration) -> {
|
||||||
final CollectionIdJdbcType jdbcTypeAnn = modelXProperty.getAnnotation( CollectionIdJdbcType.class );
|
final CollectionIdJdbcType jdbcTypeAnn = findAnnotation( modelXProperty, CollectionIdJdbcType.class );
|
||||||
if ( jdbcTypeAnn != null ) {
|
if ( jdbcTypeAnn != null ) {
|
||||||
final Class<? extends JdbcTypeDescriptor> jdbcType = normalizeJdbcType( jdbcTypeAnn.value() );
|
final Class<? extends JdbcTypeDescriptor> jdbcType = normalizeJdbcType( jdbcTypeAnn.value() );
|
||||||
if ( jdbcType != null ) {
|
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 != null ) {
|
||||||
if ( jdbcTypeCodeAnn.value() != Integer.MIN_VALUE ) {
|
if ( jdbcTypeCodeAnn.value() != Integer.MIN_VALUE ) {
|
||||||
return typeConfiguration.getJdbcTypeDescriptorRegistry().getDescriptor( jdbcTypeCodeAnn.value() );
|
return typeConfiguration.getJdbcTypeDescriptorRegistry().getDescriptor( jdbcTypeCodeAnn.value() );
|
||||||
|
@ -424,12 +427,11 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
||||||
};
|
};
|
||||||
|
|
||||||
explicitMutabilityAccess = (typeConfiguration) -> {
|
explicitMutabilityAccess = (typeConfiguration) -> {
|
||||||
final CollectionIdMutability mutabilityAnn = modelXProperty.getAnnotation( CollectionIdMutability.class );
|
final CollectionIdMutability mutabilityAnn = findAnnotation( modelXProperty, CollectionIdMutability.class );
|
||||||
if ( mutabilityAnn != null ) {
|
if ( mutabilityAnn != null ) {
|
||||||
final Class<? extends MutabilityPlan<?>> mutability = normalizeMutability( mutabilityAnn.value() );
|
final Class<? extends MutabilityPlan<?>> mutability = normalizeMutability( mutabilityAnn.value() );
|
||||||
if ( mutability != null ) {
|
if ( mutability != null ) {
|
||||||
final ManagedBean<? extends MutabilityPlan<?>> jtdBean = beanRegistry
|
final ManagedBean<? extends MutabilityPlan<?>> jtdBean = beanRegistry.getBean( mutability );
|
||||||
.getBean( mutability );
|
|
||||||
return jtdBean.getBeanInstance();
|
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 ) {
|
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 ) ) {
|
if ( converterDescriptor.getAttributeConverterClass().isAnnotationPresent( Immutable.class ) ) {
|
||||||
return ImmutableMutabilityPlan.instance();
|
return ImmutableMutabilityPlan.instance();
|
||||||
}
|
}
|
||||||
|
@ -495,7 +503,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
||||||
.getService( ManagedBeanRegistry.class );
|
.getService( ManagedBeanRegistry.class );
|
||||||
|
|
||||||
explicitJdbcTypeAccess = typeConfiguration -> {
|
explicitJdbcTypeAccess = typeConfiguration -> {
|
||||||
final MapKeyJdbcType jdbcTypeAnn = mapAttribute.getAnnotation( MapKeyJdbcType.class );
|
final MapKeyJdbcType jdbcTypeAnn = findAnnotation( mapAttribute, MapKeyJdbcType.class );
|
||||||
if ( jdbcTypeAnn != null ) {
|
if ( jdbcTypeAnn != null ) {
|
||||||
final Class<? extends JdbcTypeDescriptor> jdbcTypeImpl = normalizeJdbcType( jdbcTypeAnn.value() );
|
final Class<? extends JdbcTypeDescriptor> jdbcTypeImpl = normalizeJdbcType( jdbcTypeAnn.value() );
|
||||||
if ( jdbcTypeImpl != null ) {
|
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 ) {
|
if ( jdbcTypeCodeAnn != null ) {
|
||||||
final int jdbcTypeCode = jdbcTypeCodeAnn.value();
|
final int jdbcTypeCode = jdbcTypeCodeAnn.value();
|
||||||
if ( jdbcTypeCode != Integer.MIN_VALUE ) {
|
if ( jdbcTypeCode != Integer.MIN_VALUE ) {
|
||||||
|
@ -516,7 +524,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
||||||
};
|
};
|
||||||
|
|
||||||
explicitJavaTypeAccess = typeConfiguration -> {
|
explicitJavaTypeAccess = typeConfiguration -> {
|
||||||
final MapKeyJavaType javaTypeAnn = mapAttribute.getAnnotation( MapKeyJavaType.class );
|
final MapKeyJavaType javaTypeAnn = findAnnotation( mapAttribute, MapKeyJavaType.class );
|
||||||
if ( javaTypeAnn != null ) {
|
if ( javaTypeAnn != null ) {
|
||||||
final Class<? extends BasicJavaTypeDescriptor<?>> jdbcTypeImpl = normalizeJavaType( javaTypeAnn.value() );
|
final Class<? extends BasicJavaTypeDescriptor<?>> jdbcTypeImpl = normalizeJavaType( javaTypeAnn.value() );
|
||||||
if ( jdbcTypeImpl != null ) {
|
if ( jdbcTypeImpl != null ) {
|
||||||
|
@ -534,7 +542,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
||||||
};
|
};
|
||||||
|
|
||||||
explicitMutabilityAccess = typeConfiguration -> {
|
explicitMutabilityAccess = typeConfiguration -> {
|
||||||
final MapKeyMutability mutabilityAnn = mapAttribute.getAnnotation( MapKeyMutability.class );
|
final MapKeyMutability mutabilityAnn = findAnnotation( mapAttribute, MapKeyMutability.class );
|
||||||
if ( mutabilityAnn != null ) {
|
if ( mutabilityAnn != null ) {
|
||||||
final Class<? extends MutabilityPlan<?>> mutability = normalizeMutability( mutabilityAnn.value() );
|
final Class<? extends MutabilityPlan<?>> mutability = normalizeMutability( mutabilityAnn.value() );
|
||||||
if ( mutability != null ) {
|
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 the value is converted, see if the converter Class is annotated `@Immutable`
|
||||||
if ( converterDescriptor != null ) {
|
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 ) ) {
|
if ( converterDescriptor.getAttributeConverterClass().isAnnotationPresent( Immutable.class ) ) {
|
||||||
return ImmutableMutabilityPlan.instance();
|
return ImmutableMutabilityPlan.instance();
|
||||||
}
|
}
|
||||||
|
@ -581,7 +595,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
||||||
.getService( ManagedBeanRegistry.class );
|
.getService( ManagedBeanRegistry.class );
|
||||||
|
|
||||||
explicitJavaTypeAccess = (typeConfiguration) -> {
|
explicitJavaTypeAccess = (typeConfiguration) -> {
|
||||||
final ListIndexJavaType javaTypeAnn = listAttribute.getAnnotation( ListIndexJavaType.class );
|
final ListIndexJavaType javaTypeAnn = findAnnotation( listAttribute, ListIndexJavaType.class );
|
||||||
if ( javaTypeAnn != null ) {
|
if ( javaTypeAnn != null ) {
|
||||||
final Class<? extends BasicJavaTypeDescriptor<?>> javaType = normalizeJavaType( javaTypeAnn.value() );
|
final Class<? extends BasicJavaTypeDescriptor<?>> javaType = normalizeJavaType( javaTypeAnn.value() );
|
||||||
if ( javaType != null ) {
|
if ( javaType != null ) {
|
||||||
|
@ -594,7 +608,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
||||||
};
|
};
|
||||||
|
|
||||||
explicitJdbcTypeAccess = (typeConfiguration) -> {
|
explicitJdbcTypeAccess = (typeConfiguration) -> {
|
||||||
final ListIndexJdbcType jdbcTypeAnn = listAttribute.getAnnotation( ListIndexJdbcType.class );
|
final ListIndexJdbcType jdbcTypeAnn = findAnnotation( listAttribute, ListIndexJdbcType.class );
|
||||||
if ( jdbcTypeAnn != null ) {
|
if ( jdbcTypeAnn != null ) {
|
||||||
final Class<? extends JdbcTypeDescriptor> jdbcType = normalizeJdbcType( jdbcTypeAnn.value() );
|
final Class<? extends JdbcTypeDescriptor> jdbcType = normalizeJdbcType( jdbcTypeAnn.value() );
|
||||||
if ( jdbcType != null ) {
|
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 ) {
|
if ( jdbcTypeCodeAnn != null ) {
|
||||||
return typeConfiguration.getJdbcTypeDescriptorRegistry().getDescriptor( jdbcTypeCodeAnn.value() );
|
return typeConfiguration.getJdbcTypeDescriptorRegistry().getDescriptor( jdbcTypeCodeAnn.value() );
|
||||||
}
|
}
|
||||||
|
@ -736,7 +750,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void prepareAnyDiscriminator(XProperty modelXProperty) {
|
private void prepareAnyDiscriminator(XProperty modelXProperty) {
|
||||||
final AnyDiscriminator anyDiscriminatorAnn = modelXProperty.getAnnotation( AnyDiscriminator.class );
|
final AnyDiscriminator anyDiscriminatorAnn = findAnnotation( modelXProperty, AnyDiscriminator.class );
|
||||||
|
|
||||||
implicitJavaTypeAccess = (typeConfiguration) -> {
|
implicitJavaTypeAccess = (typeConfiguration) -> {
|
||||||
if ( anyDiscriminatorAnn != null ) {
|
if ( anyDiscriminatorAnn != null ) {
|
||||||
|
@ -783,7 +797,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
||||||
.getService( ManagedBeanRegistry.class );
|
.getService( ManagedBeanRegistry.class );
|
||||||
|
|
||||||
explicitJavaTypeAccess = (typeConfiguration) -> {
|
explicitJavaTypeAccess = (typeConfiguration) -> {
|
||||||
final AnyKeyJavaType javaTypeAnn = modelXProperty.getAnnotation( AnyKeyJavaType.class );
|
final AnyKeyJavaType javaTypeAnn = findAnnotation( modelXProperty, AnyKeyJavaType.class );
|
||||||
if ( javaTypeAnn != null ) {
|
if ( javaTypeAnn != null ) {
|
||||||
final Class<? extends BasicJavaTypeDescriptor<?>> javaType = normalizeJavaType( javaTypeAnn.value() );
|
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 ) {
|
if ( javaClassAnn != null ) {
|
||||||
//noinspection rawtypes
|
//noinspection rawtypes
|
||||||
return (BasicJavaTypeDescriptor) typeConfiguration
|
return (BasicJavaTypeDescriptor) typeConfiguration
|
||||||
|
@ -805,7 +819,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
||||||
};
|
};
|
||||||
|
|
||||||
explicitJdbcTypeAccess = (typeConfiguration) -> {
|
explicitJdbcTypeAccess = (typeConfiguration) -> {
|
||||||
final AnyKeyJdbcType jdbcTypeAnn = modelXProperty.getAnnotation( AnyKeyJdbcType.class );
|
final AnyKeyJdbcType jdbcTypeAnn = findAnnotation( modelXProperty, AnyKeyJdbcType.class );
|
||||||
if ( jdbcTypeAnn != null ) {
|
if ( jdbcTypeAnn != null ) {
|
||||||
final Class<? extends JdbcTypeDescriptor> jdbcType = normalizeJdbcType( jdbcTypeAnn.value() );
|
final Class<? extends JdbcTypeDescriptor> jdbcType = normalizeJdbcType( jdbcTypeAnn.value() );
|
||||||
if ( jdbcType != null ) {
|
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 != null ) {
|
||||||
if ( jdbcTypeCodeAnn.value() != Integer.MIN_VALUE ) {
|
if ( jdbcTypeCodeAnn.value() != Integer.MIN_VALUE ) {
|
||||||
return typeConfiguration.getJdbcTypeDescriptorRegistry().getDescriptor( jdbcTypeCodeAnn.value() );
|
return typeConfiguration.getJdbcTypeDescriptorRegistry().getDescriptor( jdbcTypeCodeAnn.value() );
|
||||||
|
@ -833,7 +847,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
||||||
.getServiceRegistry()
|
.getServiceRegistry()
|
||||||
.getService( ManagedBeanRegistry.class );
|
.getService( ManagedBeanRegistry.class );
|
||||||
|
|
||||||
final JdbcType jdbcTypeAnn = attributeXProperty.getAnnotation( JdbcType.class );
|
final JdbcType jdbcTypeAnn = findAnnotation( attributeXProperty, JdbcType.class );
|
||||||
if ( jdbcTypeAnn != null ) {
|
if ( jdbcTypeAnn != null ) {
|
||||||
final Class<? extends JdbcTypeDescriptor> jdbcType = normalizeJdbcType( jdbcTypeAnn.value() );
|
final Class<? extends JdbcTypeDescriptor> jdbcType = normalizeJdbcType( jdbcTypeAnn.value() );
|
||||||
if ( jdbcType != null ) {
|
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 ) {
|
if ( jdbcTypeCodeAnn != null ) {
|
||||||
final int jdbcTypeCode = jdbcTypeCodeAnn.value();
|
final int jdbcTypeCode = jdbcTypeCodeAnn.value();
|
||||||
if ( jdbcTypeCode != Integer.MIN_VALUE ) {
|
if ( jdbcTypeCode != Integer.MIN_VALUE ) {
|
||||||
|
@ -862,7 +876,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
||||||
.getService( ManagedBeanRegistry.class );
|
.getService( ManagedBeanRegistry.class );
|
||||||
|
|
||||||
explicitMutabilityAccess = typeConfiguration -> {
|
explicitMutabilityAccess = typeConfiguration -> {
|
||||||
final Mutability mutabilityAnn = attributeXProperty.getAnnotation( Mutability.class );
|
final Mutability mutabilityAnn = findAnnotation( attributeXProperty, Mutability.class );
|
||||||
if ( mutabilityAnn != null ) {
|
if ( mutabilityAnn != null ) {
|
||||||
final Class<? extends MutabilityPlan<?>> mutability = normalizeMutability( mutabilityAnn.value() );
|
final Class<? extends MutabilityPlan<?>> mutability = normalizeMutability( mutabilityAnn.value() );
|
||||||
if ( mutability != null ) {
|
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 the value is converted, see if the converter Class is annotated `@Immutable`
|
||||||
if ( converterDescriptor != null ) {
|
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 ) ) {
|
if ( converterDescriptor.getAttributeConverterClass().isAnnotationPresent( Immutable.class ) ) {
|
||||||
return ImmutableMutabilityPlan.instance();
|
return ImmutableMutabilityPlan.instance();
|
||||||
}
|
}
|
||||||
|
@ -913,7 +933,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
||||||
.getService( ManagedBeanRegistry.class );
|
.getService( ManagedBeanRegistry.class );
|
||||||
|
|
||||||
explicitJavaTypeAccess = typeConfiguration -> {
|
explicitJavaTypeAccess = typeConfiguration -> {
|
||||||
final JavaType javaTypeAnn = attributeXProperty.getAnnotation( JavaType.class );
|
final JavaType javaTypeAnn = findAnnotation( attributeXProperty, JavaType.class );
|
||||||
if ( javaTypeAnn != null ) {
|
if ( javaTypeAnn != null ) {
|
||||||
final Class<? extends BasicJavaTypeDescriptor<?>> javaType = normalizeJavaType( javaTypeAnn.value() );
|
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;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1095,10 +1122,6 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
||||||
basicValue.setTemporalPrecision( temporalPrecision );
|
basicValue.setTemporalPrecision( temporalPrecision );
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo (6.0) : explicit SqlTypeDescriptor / JDBC type-code
|
|
||||||
// todo (6.0) : explicit mutability / immutable
|
|
||||||
// todo (6.0) : explicit Comparator
|
|
||||||
|
|
||||||
linkWithValue();
|
linkWithValue();
|
||||||
|
|
||||||
boolean isInSecondPass = buildingContext.getMetadataCollector().isInSecondPass();
|
boolean isInSecondPass = buildingContext.getMetadataCollector().isInSecondPass();
|
||||||
|
@ -1285,7 +1308,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<? extends UserType<?>> customType(XProperty xProperty) {
|
public Class<? extends UserType<?>> customType(XProperty xProperty) {
|
||||||
final CustomType customType = xProperty.getAnnotation( CustomType.class );
|
final CustomType customType = findAnnotation( xProperty, CustomType.class );
|
||||||
if ( customType == null ) {
|
if ( customType == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1295,7 +1318,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Parameter[] customTypeParameters(XProperty xProperty) {
|
public Parameter[] customTypeParameters(XProperty xProperty) {
|
||||||
final CustomType customType = xProperty.getAnnotation( CustomType.class );
|
final CustomType customType = findAnnotation( xProperty, CustomType.class );
|
||||||
if ( customType == null ) {
|
if ( customType == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1340,7 +1363,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<? extends UserType<?>> customType(XProperty xProperty) {
|
public Class<? extends UserType<?>> customType(XProperty xProperty) {
|
||||||
final MapKeyCustomType customType = xProperty.getAnnotation( MapKeyCustomType.class );
|
final MapKeyCustomType customType = findAnnotation( xProperty, MapKeyCustomType.class );
|
||||||
if ( customType == null ) {
|
if ( customType == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1350,7 +1373,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Parameter[] customTypeParameters(XProperty xProperty) {
|
public Parameter[] customTypeParameters(XProperty xProperty) {
|
||||||
final MapKeyCustomType customType = xProperty.getAnnotation( MapKeyCustomType.class );
|
final MapKeyCustomType customType = findAnnotation( xProperty, MapKeyCustomType.class );
|
||||||
if ( customType == null ) {
|
if ( customType == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1363,7 +1386,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<? extends UserType<?>> customType(XProperty xProperty) {
|
public Class<? extends UserType<?>> customType(XProperty xProperty) {
|
||||||
final CollectionIdCustomType customType = xProperty.getAnnotation( CollectionIdCustomType.class );
|
final CollectionIdCustomType customType = findAnnotation( xProperty, CollectionIdCustomType.class );
|
||||||
if ( customType == null ) {
|
if ( customType == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1373,7 +1396,7 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Parameter[] customTypeParameters(XProperty xProperty) {
|
public Parameter[] customTypeParameters(XProperty xProperty) {
|
||||||
final CollectionIdCustomType customType = xProperty.getAnnotation( CollectionIdCustomType.class );
|
final CollectionIdCustomType customType = findAnnotation( xProperty, CollectionIdCustomType.class );
|
||||||
if ( customType == null ) {
|
if ( customType == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,11 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.cfg.annotations;
|
package org.hibernate.cfg.annotations;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Member;
|
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.XProperty;
|
||||||
import org.hibernate.annotations.common.reflection.java.JavaXMember;
|
import org.hibernate.annotations.common.reflection.java.JavaXMember;
|
||||||
|
|
||||||
|
@ -16,6 +19,7 @@ import org.hibernate.annotations.common.reflection.java.JavaXMember;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
|
@Internal
|
||||||
public final class HCANNHelper {
|
public final class HCANNHelper {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,4 +51,35 @@ public final class HCANNHelper {
|
||||||
public static Member getUnderlyingMember(final JavaXMember jxProperty) {
|
public static Member getUnderlyingMember(final JavaXMember jxProperty) {
|
||||||
return jxProperty.getMember();
|
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.AfterEach;
|
||||||
import org.junit.jupiter.api.Test;
|
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.GENERATE_STATISTICS;
|
||||||
import static org.hibernate.cfg.AvailableSettings.USE_QUERY_CACHE;
|
import static org.hibernate.cfg.AvailableSettings.USE_QUERY_CACHE;
|
||||||
import static org.hibernate.cfg.AvailableSettings.USE_SECOND_LEVEL_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.assertNotNull;
|
||||||
import static org.junit.Assert.assertNotSame;
|
import static org.junit.Assert.assertNotSame;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
|
@ -353,7 +351,7 @@ public class MutableNaturalIdTest {
|
||||||
.using( "name", "steve" )
|
.using( "name", "steve" )
|
||||||
.using( "org", "hb" )
|
.using( "org", "hb" )
|
||||||
.load();
|
.load();
|
||||||
assertNotNull( u );
|
assertNotNull( beforeEvict );
|
||||||
assertEquals( statistics.getPrepareStatementCount(), 1 );
|
assertEquals( statistics.getPrepareStatementCount(), 1 );
|
||||||
|
|
||||||
session.evict( beforeEvict );
|
session.evict( beforeEvict );
|
||||||
|
|
|
@ -14,6 +14,7 @@ import java.lang.annotation.Target;
|
||||||
|
|
||||||
import jakarta.persistence.SharedCacheMode;
|
import jakarta.persistence.SharedCacheMode;
|
||||||
|
|
||||||
|
import org.hibernate.boot.model.TypeContributor;
|
||||||
import org.hibernate.cache.spi.access.AccessType;
|
import org.hibernate.cache.spi.access.AccessType;
|
||||||
|
|
||||||
import org.hibernate.testing.orm.domain.DomainModelDescriptor;
|
import org.hibernate.testing.orm.domain.DomainModelDescriptor;
|
||||||
|
@ -108,6 +109,8 @@ public @interface DomainModel {
|
||||||
|
|
||||||
AccessType accessType() default AccessType.READ_WRITE;
|
AccessType accessType() default AccessType.READ_WRITE;
|
||||||
|
|
||||||
|
Class<? extends TypeContributor>[] typeContributors() default {};
|
||||||
|
|
||||||
@interface ExtraQueryImport {
|
@interface ExtraQueryImport {
|
||||||
String name();
|
String name();
|
||||||
Class<?> importedClass();
|
Class<?> importedClass();
|
||||||
|
|
|
@ -14,14 +14,16 @@ import java.util.Optional;
|
||||||
|
|
||||||
import org.hibernate.boot.Metadata;
|
import org.hibernate.boot.Metadata;
|
||||||
import org.hibernate.boot.MetadataSources;
|
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.registry.StandardServiceRegistry;
|
||||||
import org.hibernate.boot.spi.MetadataImplementor;
|
import org.hibernate.boot.spi.MetadataImplementor;
|
||||||
import org.hibernate.internal.util.JavaHelper;
|
|
||||||
import org.hibernate.mapping.Collection;
|
import org.hibernate.mapping.Collection;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
import org.hibernate.mapping.Property;
|
import org.hibernate.mapping.Property;
|
||||||
import org.hibernate.mapping.RootClass;
|
import org.hibernate.mapping.RootClass;
|
||||||
import org.hibernate.mapping.SimpleValue;
|
import org.hibernate.mapping.SimpleValue;
|
||||||
|
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
|
||||||
import org.hibernate.type.BlobType;
|
import org.hibernate.type.BlobType;
|
||||||
import org.hibernate.type.ClobType;
|
import org.hibernate.type.ClobType;
|
||||||
import org.hibernate.type.NClobType;
|
import org.hibernate.type.NClobType;
|
||||||
|
@ -88,6 +90,7 @@ public class DomainModelExtension
|
||||||
final DomainModel domainModelAnnotation = domainModelAnnotationWrapper.get();
|
final DomainModel domainModelAnnotation = domainModelAnnotationWrapper.get();
|
||||||
|
|
||||||
final MetadataSources metadataSources = new MetadataSources( serviceRegistry );
|
final MetadataSources metadataSources = new MetadataSources( serviceRegistry );
|
||||||
|
final ManagedBeanRegistry managedBeanRegistry = serviceRegistry.getService( ManagedBeanRegistry.class );
|
||||||
|
|
||||||
for ( String annotatedPackageName : domainModelAnnotation.annotatedPackageNames() ) {
|
for ( String annotatedPackageName : domainModelAnnotation.annotatedPackageNames() ) {
|
||||||
metadataSources.addPackage( annotatedPackageName );
|
metadataSources.addPackage( annotatedPackageName );
|
||||||
|
@ -127,12 +130,20 @@ public class DomainModelExtension
|
||||||
metadataSources.addQueryImport( importedClass.getSimpleName(), importedClass );
|
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(
|
applyCacheSettings(
|
||||||
metadataImplementor,
|
metadataImplementor,
|
||||||
domainModelAnnotation.overrideCacheStrategy(),
|
domainModelAnnotation.overrideCacheStrategy(),
|
||||||
domainModelAnnotation.concurrencyStrategy()
|
domainModelAnnotation.concurrencyStrategy()
|
||||||
);
|
);
|
||||||
|
|
||||||
return metadataImplementor;
|
return metadataImplementor;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue