HHH-18728 - Allow mixed discriminator-value mappings for ANY
HHH-18729 - Allow custom strategy for implicit discriminator-value determination for ANY
This commit is contained in:
parent
046557fe15
commit
2ea226999d
|
@ -3,6 +3,7 @@
|
||||||
:root-project-dir: ../../../../../../..
|
:root-project-dir: ../../../../../../..
|
||||||
:core-project-dir: {root-project-dir}/hibernate-core
|
:core-project-dir: {root-project-dir}/hibernate-core
|
||||||
:example-dir-association: {core-project-dir}/src/test/java/org/hibernate/orm/test/associations
|
:example-dir-association: {core-project-dir}/src/test/java/org/hibernate/orm/test/associations
|
||||||
|
:example-dir-any: {core-project-dir}/src/test/java/org/hibernate/orm/test/any
|
||||||
:extrasdir: extras/associations
|
:extrasdir: extras/associations
|
||||||
|
|
||||||
Associations describe how two or more entities form a relationship based on a database joining semantics.
|
Associations describe how two or more entities form a relationship based on a database joining semantics.
|
||||||
|
@ -559,7 +560,7 @@ The `@Any` mapping is useful to emulate a unidirectional `@ManyToOne` associatio
|
||||||
|
|
||||||
Because the `@Any` mapping defines a polymorphic association to classes from multiple tables,
|
Because the `@Any` mapping defines a polymorphic association to classes from multiple tables,
|
||||||
this association type requires the FK column which provides the associated parent identifier and
|
this association type requires the FK column which provides the associated parent identifier and
|
||||||
a metadata information for the associated entity type.
|
a discriminator which identifies the associated entity type.
|
||||||
|
|
||||||
[NOTE]
|
[NOTE]
|
||||||
====
|
====
|
||||||
|
@ -568,16 +569,33 @@ This is not the usual way of mapping polymorphic associations and you should use
|
||||||
|
|
||||||
To map such an association, Hibernate needs to understand 3 things:
|
To map such an association, Hibernate needs to understand 3 things:
|
||||||
|
|
||||||
1. The column and mapping for the discriminator
|
1. The column and mapping for the <<associations-any-discriminator,discriminator>>
|
||||||
2. The column and mapping for the key
|
2. The column and mapping for the <<associations-any-key,key>>
|
||||||
3. The mapping between discriminator values and entity classes
|
3. The mapping between discriminator values and entity types which may be <<associations-any-explicit-discriminator,explicit>>
|
||||||
|
<<associations-any-implicit-discriminator,implicit>> or <<associations-any-mixed-discriminator,mixed>>.
|
||||||
|
|
||||||
|
For the rest of this discussion, consider the following model which will be the target types for the `@Any` associations:
|
||||||
|
|
||||||
|
[[associations-any-target-example]]
|
||||||
|
.`Payment` class hierarchy
|
||||||
|
====
|
||||||
|
[source, java, indent=0]
|
||||||
|
----
|
||||||
|
include::{example-dir-any}/discriminator/Payment.java[tags=associations-any-example]
|
||||||
|
|
||||||
|
include::{example-dir-any}/discriminator/CardPayment.java[tags=associations-any-example]
|
||||||
|
|
||||||
|
include::{example-dir-any}/discriminator/CashPayment.java[tags=associations-any-example]
|
||||||
|
|
||||||
|
include::{example-dir-any}/discriminator/CheckPayment.java[tags=associations-any-example]
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
|
||||||
[[associations-any-discriminator]]
|
[[associations-any-discriminator]]
|
||||||
===== The discriminator
|
===== The discriminator
|
||||||
|
|
||||||
The discriminator of an any-style association holds the value that indicates which entity is
|
The discriminator is the value that indicates which entity is referred to by a row.
|
||||||
referred to by a row.
|
|
||||||
|
|
||||||
Its "column" can be specified with either `@Column` or `@Formula`. The mapping type can be influenced by any of:
|
Its "column" can be specified with either `@Column` or `@Formula`. The mapping type can be influenced by any of:
|
||||||
|
|
||||||
|
@ -601,114 +619,105 @@ type can be influenced by any of:
|
||||||
4. `@AnyKeyJdbcTypeCode`
|
4. `@AnyKeyJdbcTypeCode`
|
||||||
|
|
||||||
|
|
||||||
[[associations-any-values]]
|
|
||||||
===== The discriminator value mappings
|
|
||||||
|
|
||||||
`@AnyDiscriminatorValue` is used to map the discriminator values to the corresponding entity classes
|
[[associations-any-explicit-discriminator]]
|
||||||
|
===== Explicit discriminator mappings
|
||||||
|
|
||||||
|
Explicit discriminator mappings are defined using one-or-more `@AnyDiscriminatorValue` annotations. E.g.
|
||||||
|
|
||||||
|
|
||||||
[[associations-any-property]]
|
[[associations-any-discriminator-explicit-example]]
|
||||||
==== Example using @Any mapping
|
.Explicit @AnyDiscriminatorValue annotations
|
||||||
|
|
||||||
For this example, consider the following `Property` class hierarchy:
|
|
||||||
|
|
||||||
[[associations-any-property-example]]
|
|
||||||
.`Property` class hierarchy
|
|
||||||
====
|
====
|
||||||
[source, java, indent=0]
|
[source, java, indent=0]
|
||||||
----
|
----
|
||||||
include::{example-dir-association}/any/Property.java[tags=associations-any-property-example]
|
include::{example-dir-any}/discriminator/explicit/Order.java[tags=associations-any-explicit-discriminator-example]
|
||||||
|
|
||||||
include::{example-dir-association}/any/IntegerProperty.java[tags=associations-any-property-example]
|
|
||||||
|
|
||||||
include::{example-dir-association}/any/StringProperty.java[tags=associations-any-property-example]
|
|
||||||
----
|
----
|
||||||
====
|
====
|
||||||
|
|
||||||
A `PropertyHolder` entity defines an attribute of type `Property`:
|
Here, we map 2 explicit discriminator value mappings:
|
||||||
|
|
||||||
[[associations-any-example]]
|
1. `CARD` <-> `CardPayment`
|
||||||
.`@Any` mapping usage
|
2. `CHECK` <-> `CheckPayment`
|
||||||
|
|
||||||
|
Notice that `CashPayment` is not explicitly mapped. An attempt to use `CashPayment` for this attribute will result
|
||||||
|
in an exception.
|
||||||
|
|
||||||
|
|
||||||
|
[[associations-any-implicit-discriminator]]
|
||||||
|
===== Implicit discriminator mappings
|
||||||
|
|
||||||
|
Implicit discriminator mappings define no `@AnyDiscriminatorValue` annotations. E.g.
|
||||||
|
|
||||||
|
[[associations-any-discriminator-implicit-example]]
|
||||||
|
.Implicit @Any discriminator mappings
|
||||||
====
|
====
|
||||||
[source, java, indent=0]
|
[source, java, indent=0]
|
||||||
----
|
----
|
||||||
include::{example-dir-association}/any/PropertyHolder.java[tags=associations-any-example]
|
include::{example-dir-any}/discriminator/implicit/Order.java[tags=associations-any-implicit-discriminator-example]
|
||||||
----
|
|
||||||
|
|
||||||
[source, SQL, indent=0]
|
|
||||||
----
|
|
||||||
include::{extrasdir}/associations-any-example.sql[]
|
|
||||||
----
|
----
|
||||||
====
|
====
|
||||||
|
|
||||||
`PropertyHolder#property` can refer to either `StringProperty` or `IntegerProperty` references, as indicated
|
Here all `Payment` subtypes are allowed. By default Hibernate will use the entity's full-name (which is generally the class's FQN).
|
||||||
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`.
|
Hibernate also offers a `@AnyDiscriminatorImplicitValues` annotation which allows configuration of how this implicit
|
||||||
The `property_id` is used to match the `id` column of either the `string_property` or `integer_property` tables,
|
mapping works. E.g., to use the entity's short-name instead of the full-name -
|
||||||
while the `property_type` is used to match the `string_property` or the `integer_property` table.
|
|
||||||
|
|
||||||
To see the `@Any` annotation in action, consider the next examples.
|
|
||||||
|
|
||||||
If we persist an `IntegerProperty` as well as a `StringProperty` entity, and associate
|
[[associations-any-discriminator-implicit-short-example]]
|
||||||
the `StringProperty` entity with a `PropertyHolder`,
|
.Implicit @Any discriminator mappings (short name)
|
||||||
Hibernate will generate the following SQL queries:
|
|
||||||
|
|
||||||
[[associations-any-persist-example]]
|
|
||||||
.`@Any` mapping persist example
|
|
||||||
====
|
====
|
||||||
[source, java, indent=0]
|
[source, java, indent=0]
|
||||||
----
|
----
|
||||||
include::{example-dir-association}/any/AnyTest.java[tags=associations-any-persist-example]
|
include::{example-dir-any}/discriminator/implicit/Order.java[tags=associations-any-implicit-discriminator-short-example]
|
||||||
----
|
|
||||||
|
|
||||||
[source, SQL, indent=0]
|
|
||||||
----
|
|
||||||
include::{extrasdir}/associations-any-persist-example.sql[]
|
|
||||||
----
|
----
|
||||||
====
|
====
|
||||||
|
|
||||||
When fetching the `PropertyHolder` entity and navigating its `property` association,
|
[NOTE]
|
||||||
Hibernate will fetch the associated `StringProperty` entity like this:
|
====
|
||||||
|
`@AnyDiscriminatorImplicitValues` also offers the ability to define a custom strategy for determining the
|
||||||
|
discriminator-value <-> entity-type mapping, but its use is not covered here.
|
||||||
|
====
|
||||||
|
|
||||||
[[associations-any-query-example]]
|
|
||||||
.`@Any` mapping query example
|
[[associations-any-mixed-discriminator]]
|
||||||
|
===== Mixed discriminator mappings
|
||||||
|
|
||||||
|
A mixed strategy combines `@AnyDiscriminatorValue` and `@AnyDiscriminatorImplicitValues`. Mappings
|
||||||
|
explicitly defined using `@AnyDiscriminatorValue` take precedence. E.g.
|
||||||
|
|
||||||
|
|
||||||
|
[[associations-any-discriminator-mixed-example]]
|
||||||
|
.Mixed @Any discriminator mappings (short name)
|
||||||
====
|
====
|
||||||
[source, java, indent=0]
|
[source, java, indent=0]
|
||||||
----
|
----
|
||||||
include::{example-dir-association}/any/AnyTest.java[tags=associations-any-query-example]
|
include::{example-dir-any}/discriminator/mixed/Order.java[tags=associations-any-mixed-discriminator-short-example]
|
||||||
----
|
|
||||||
|
|
||||||
[source, SQL, indent=0]
|
|
||||||
----
|
|
||||||
include::{extrasdir}/associations-any-query-example.sql[]
|
|
||||||
----
|
----
|
||||||
====
|
====
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[associations-any-meta-annotations]]
|
[[associations-any-meta-annotations]]
|
||||||
===== Using meta-annotations
|
===== Using meta-annotations
|
||||||
|
|
||||||
As mentioned in <<basic-mapping>>, Hibernate's ANY-related annotations can be composed 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.
|
to re-use ANY mapping details.
|
||||||
|
|
||||||
Looking back at <<associations-any-example>>, we can see how cumbersome it would be to duplicate that
|
Given all the details needed to define an ANY mapping, 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
|
information every time `Payment` is mapped in the domain model. This description can also be moved
|
||||||
into a single annotation that we can apply in each usage.
|
into a single annotation that we can apply in each usage.
|
||||||
|
|
||||||
|
|
||||||
[[associations-any-composed-example]]
|
[[associations-any-composed-example]]
|
||||||
.`@Any` mapping usage
|
.`@Any` mapping with meta-annotation
|
||||||
====
|
====
|
||||||
[source, java, indent=0]
|
[source, java, indent=0]
|
||||||
----
|
----
|
||||||
include::{example-dir-association}/any/PropertyHolder2.java[tags=associations-any-def-example]
|
include::{example-dir-any}/discriminator/meta/Order.java[tags=associations-any-discriminator-meta-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]]
|
||||||
|
@ -724,16 +733,16 @@ The mapping details are the same between `@Any` and `@ManyToAny` except for:
|
||||||
of just `@JoinColumn`
|
of just `@JoinColumn`
|
||||||
|
|
||||||
|
|
||||||
In the following example, the `PropertyRepository` entity has a collection of `Property` entities.
|
In the following example, the `Loan` entity has a collection of `Payments` objects.
|
||||||
|
|
||||||
The `repository_properties` link table holds the associations between `PropertyRepository` and `Property` entities.
|
The `loan_payments` table holds the associations between `Loan` and `Payment` references.
|
||||||
|
|
||||||
[[associations-many-to-any-example]]
|
[[associations-many-to-any-example]]
|
||||||
.`@ManyToAny` mapping usage
|
.`@ManyToAny` mapping usage
|
||||||
====
|
====
|
||||||
[source, java, indent=0]
|
[source, java, indent=0]
|
||||||
----
|
----
|
||||||
include::{example-dir-association}/any/PropertyRepository.java[tags=associations-many-to-any-example]
|
include::{example-dir-any}/discriminator/many/Loan.java[tags=associations-many-to-any-example]
|
||||||
----
|
----
|
||||||
|
|
||||||
[source, SQL, indent=0]
|
[source, SQL, indent=0]
|
||||||
|
@ -742,43 +751,6 @@ include::{extrasdir}/associations-many-to-any-example.sql[]
|
||||||
----
|
----
|
||||||
====
|
====
|
||||||
|
|
||||||
To see the `@ManyToAny` annotation in action, consider the next examples.
|
|
||||||
|
|
||||||
If we persist an `IntegerProperty` as well as a `StringProperty` entity,
|
|
||||||
and associate both of them with a `PropertyRepository` parent entity,
|
|
||||||
Hibernate will generate the following SQL queries:
|
|
||||||
|
|
||||||
[[associations-many-to-any-persist-example]]
|
|
||||||
.`@ManyToAny` mapping persist example
|
|
||||||
====
|
|
||||||
[source, java, indent=0]
|
|
||||||
----
|
|
||||||
include::{example-dir-association}/any/ManyToAnyTest.java[tags=associations-many-to-any-persist-example]
|
|
||||||
----
|
|
||||||
|
|
||||||
[source, SQL, indent=0]
|
|
||||||
----
|
|
||||||
include::{extrasdir}/associations-many-to-any-persist-example.sql[]
|
|
||||||
----
|
|
||||||
====
|
|
||||||
|
|
||||||
When fetching the `PropertyRepository` entity and navigating its `properties` association,
|
|
||||||
Hibernate will fetch the associated `IntegerProperty` and `StringProperty` entities like this:
|
|
||||||
|
|
||||||
[[associations-many-to-any-query-example]]
|
|
||||||
.`@ManyToAny` mapping query example
|
|
||||||
====
|
|
||||||
[source, java, indent=0]
|
|
||||||
----
|
|
||||||
include::{example-dir-association}/any/ManyToAnyTest.java[tags=associations-many-to-any-query-example]
|
|
||||||
----
|
|
||||||
|
|
||||||
[source, SQL, indent=0]
|
|
||||||
----
|
|
||||||
include::{extrasdir}/associations-many-to-any-query-example.sql[]
|
|
||||||
----
|
|
||||||
====
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[associations-JoinFormula]]
|
[[associations-JoinFormula]]
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
CREATE TABLE property_holder (
|
|
||||||
id BIGINT NOT NULL,
|
|
||||||
property_type VARCHAR(255),
|
|
||||||
property_id BIGINT,
|
|
||||||
PRIMARY KEY ( id )
|
|
||||||
)
|
|
|
@ -1,11 +0,0 @@
|
||||||
INSERT INTO integer_property
|
|
||||||
( "name", "value", id )
|
|
||||||
VALUES ( 'age', 23, 1 )
|
|
||||||
|
|
||||||
INSERT INTO string_property
|
|
||||||
( "name", "value", id )
|
|
||||||
VALUES ( 'name', 'John Doe', 1 )
|
|
||||||
|
|
||||||
INSERT INTO property_holder
|
|
||||||
( property_type, property_id, id )
|
|
||||||
VALUES ( 'S', 1, 1 )
|
|
|
@ -1,12 +0,0 @@
|
||||||
SELECT ph.id AS id1_1_0_,
|
|
||||||
ph.property_type AS property2_1_0_,
|
|
||||||
ph.property_id AS property3_1_0_
|
|
||||||
FROM property_holder ph
|
|
||||||
WHERE ph.id = 1
|
|
||||||
|
|
||||||
|
|
||||||
SELECT sp.id AS id1_2_0_,
|
|
||||||
sp."name" AS name2_2_0_,
|
|
||||||
sp."value" AS value3_2_0_
|
|
||||||
FROM string_property sp
|
|
||||||
WHERE sp.id = 1
|
|
|
@ -1,10 +1,11 @@
|
||||||
CREATE TABLE property_repository (
|
CREATE TABLE loans (
|
||||||
id BIGINT NOT NULL,
|
id BIGINT NOT NULL,
|
||||||
|
...,
|
||||||
PRIMARY KEY ( id )
|
PRIMARY KEY ( id )
|
||||||
)
|
)
|
||||||
|
|
||||||
CREATE TABLE repository_properties (
|
CREATE TABLE loan_payments (
|
||||||
repository_id BIGINT NOT NULL,
|
loan_fk BIGINT NOT NULL,
|
||||||
property_type VARCHAR(255),
|
payment_type VARCHAR(255),
|
||||||
property_id BIGINT NOT NULL
|
payment_fk BIGINT NOT NULL
|
||||||
)
|
)
|
|
@ -1,15 +0,0 @@
|
||||||
INSERT INTO integer_property
|
|
||||||
( "name", "value", id )
|
|
||||||
VALUES ( 'age', 23, 1 )
|
|
||||||
|
|
||||||
INSERT INTO string_property
|
|
||||||
( "name", "value", id )
|
|
||||||
VALUES ( 'name', 'John Doe', 1 )
|
|
||||||
|
|
||||||
INSERT INTO property_repository ( id )
|
|
||||||
VALUES ( 1 )
|
|
||||||
|
|
||||||
INSERT INTO repository_properties
|
|
||||||
( repository_id , property_type , property_id )
|
|
||||||
VALUES
|
|
||||||
( 1 , 'I' , 1 )
|
|
|
@ -1,15 +0,0 @@
|
||||||
SELECT pr.id AS id1_1_0_
|
|
||||||
FROM property_repository pr
|
|
||||||
WHERE pr.id = 1
|
|
||||||
|
|
||||||
SELECT ip.id AS id1_0_0_ ,
|
|
||||||
ip."name" AS name2_0_0_ ,
|
|
||||||
ip."value" AS value3_0_0_
|
|
||||||
FROM integer_property ip
|
|
||||||
WHERE ip.id = 1
|
|
||||||
|
|
||||||
SELECT sp.id AS id1_3_0_ ,
|
|
||||||
sp."name" AS name2_3_0_ ,
|
|
||||||
sp."value" AS value3_3_0_
|
|
||||||
FROM string_property sp
|
|
||||||
WHERE sp.id = 1
|
|
|
@ -4,17 +4,15 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.annotations;
|
package org.hibernate.annotations;
|
||||||
|
|
||||||
|
import jakarta.persistence.DiscriminatorType;
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
import jakarta.persistence.DiscriminatorType;
|
|
||||||
import org.hibernate.type.AnyDiscriminatorValueStrategy;
|
|
||||||
|
|
||||||
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.RetentionPolicy.RUNTIME;
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
import static org.hibernate.type.AnyDiscriminatorValueStrategy.AUTO;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simplified way to specify the type of the discriminator in an {@link Any}
|
* A simplified way to specify the type of the discriminator in an {@link Any}
|
||||||
|
@ -34,6 +32,8 @@ import static org.hibernate.type.AnyDiscriminatorValueStrategy.AUTO;
|
||||||
* {@code @AnyDiscriminator}.
|
* {@code @AnyDiscriminator}.
|
||||||
*
|
*
|
||||||
* @see Any
|
* @see Any
|
||||||
|
* @see AnyDiscriminatorValue
|
||||||
|
* @see AnyDiscriminatorImplicitValues
|
||||||
*
|
*
|
||||||
* @since 6.0
|
* @since 6.0
|
||||||
*/
|
*/
|
||||||
|
@ -46,12 +46,4 @@ public @interface AnyDiscriminator {
|
||||||
* or {@link JdbcTypeCode}.
|
* or {@link JdbcTypeCode}.
|
||||||
*/
|
*/
|
||||||
DiscriminatorType value() default DiscriminatorType.STRING;
|
DiscriminatorType value() default DiscriminatorType.STRING;
|
||||||
|
|
||||||
/**
|
|
||||||
* How the discriminator value should be handled in regard to explicit
|
|
||||||
* {@linkplain AnyDiscriminatorValue} mappings, if any.
|
|
||||||
*
|
|
||||||
* @since 7.0
|
|
||||||
*/
|
|
||||||
AnyDiscriminatorValueStrategy valueStrategy() default AUTO;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.annotations;
|
||||||
|
|
||||||
|
import org.hibernate.Incubating;
|
||||||
|
import org.hibernate.metamodel.internal.FullNameImplicitDiscriminatorStrategy;
|
||||||
|
import org.hibernate.metamodel.internal.ShortNameImplicitDiscriminatorStrategy;
|
||||||
|
import org.hibernate.metamodel.spi.ImplicitDiscriminatorStrategy;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
||||||
|
import static java.lang.annotation.ElementType.FIELD;
|
||||||
|
import static java.lang.annotation.ElementType.METHOD;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines how to handle {@linkplain AnyDiscriminator discriminator} values which are not explicitly
|
||||||
|
* mapped with {@linkplain AnyDiscriminatorValue}.
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
* @since 7.0
|
||||||
|
*/
|
||||||
|
@Target({METHOD, FIELD, ANNOTATION_TYPE})
|
||||||
|
@Retention( RUNTIME )
|
||||||
|
@Incubating
|
||||||
|
public @interface AnyDiscriminatorImplicitValues {
|
||||||
|
enum Strategy {
|
||||||
|
/**
|
||||||
|
* Use the {@link ImplicitDiscriminatorStrategy} implementation specified by {@link #implementation()}
|
||||||
|
*/
|
||||||
|
CUSTOM,
|
||||||
|
/**
|
||||||
|
* Use the entity's short-name.
|
||||||
|
*
|
||||||
|
* @see ShortNameImplicitDiscriminatorStrategy
|
||||||
|
*/
|
||||||
|
SHORT_NAME,
|
||||||
|
/**
|
||||||
|
* Use the entity's full-name.
|
||||||
|
*
|
||||||
|
* @see FullNameImplicitDiscriminatorStrategy
|
||||||
|
*/
|
||||||
|
FULL_NAME
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of strategy to use. This is {@link Strategy#CUSTOM} by default and
|
||||||
|
* the class named by {@link #implementation()} is used.
|
||||||
|
*/
|
||||||
|
Strategy value() default Strategy.CUSTOM;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specific strategy implementation to use, when combined with {@code value=CUSTOM}
|
||||||
|
*/
|
||||||
|
Class<? extends ImplicitDiscriminatorStrategy> implementation() default ImplicitDiscriminatorStrategy.class;
|
||||||
|
}
|
|
@ -27,6 +27,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
*
|
*
|
||||||
* @see Any
|
* @see Any
|
||||||
* @see AnyDiscriminator
|
* @see AnyDiscriminator
|
||||||
|
* @see AnyDiscriminatorImplicitValues
|
||||||
*
|
*
|
||||||
* @since 6.0
|
* @since 6.0
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -9,6 +9,7 @@ import java.util.Locale;
|
||||||
import org.hibernate.AnnotationException;
|
import org.hibernate.AnnotationException;
|
||||||
import org.hibernate.AssertionFailure;
|
import org.hibernate.AssertionFailure;
|
||||||
import org.hibernate.annotations.AnyDiscriminator;
|
import org.hibernate.annotations.AnyDiscriminator;
|
||||||
|
import org.hibernate.annotations.AnyDiscriminatorImplicitValues;
|
||||||
import org.hibernate.annotations.Cascade;
|
import org.hibernate.annotations.Cascade;
|
||||||
import org.hibernate.annotations.Columns;
|
import org.hibernate.annotations.Columns;
|
||||||
import org.hibernate.annotations.Formula;
|
import org.hibernate.annotations.Formula;
|
||||||
|
@ -19,6 +20,9 @@ import org.hibernate.boot.spi.PropertyData;
|
||||||
import org.hibernate.mapping.Any;
|
import org.hibernate.mapping.Any;
|
||||||
import org.hibernate.mapping.Join;
|
import org.hibernate.mapping.Join;
|
||||||
import org.hibernate.mapping.Property;
|
import org.hibernate.mapping.Property;
|
||||||
|
import org.hibernate.metamodel.internal.FullNameImplicitDiscriminatorStrategy;
|
||||||
|
import org.hibernate.metamodel.internal.ShortNameImplicitDiscriminatorStrategy;
|
||||||
|
import org.hibernate.metamodel.spi.ImplicitDiscriminatorStrategy;
|
||||||
import org.hibernate.models.spi.MemberDetails;
|
import org.hibernate.models.spi.MemberDetails;
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
|
@ -109,8 +113,9 @@ public class AnyBinder {
|
||||||
);
|
);
|
||||||
|
|
||||||
final AnyDiscriminator anyDiscriminator = property.getDirectAnnotationUsage( AnyDiscriminator.class );
|
final AnyDiscriminator anyDiscriminator = property.getDirectAnnotationUsage( AnyDiscriminator.class );
|
||||||
if ( anyDiscriminator != null ) {
|
final AnyDiscriminatorImplicitValues anyDiscriminatorImplicitValues = property.getDirectAnnotationUsage( AnyDiscriminatorImplicitValues.class );
|
||||||
value.setDiscriminatorValueStrategy( anyDiscriminator.valueStrategy() );
|
if ( anyDiscriminatorImplicitValues != null ) {
|
||||||
|
value.setImplicitDiscriminatorValueStrategy( resolveImplicitDiscriminatorStrategy( anyDiscriminatorImplicitValues, context ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
final PropertyBinder binder = new PropertyBinder();
|
final PropertyBinder binder = new PropertyBinder();
|
||||||
|
@ -134,4 +139,36 @@ public class AnyBinder {
|
||||||
propertyHolder.addProperty( prop, inferredData.getAttributeMember(), columns, inferredData.getDeclaringClass() );
|
propertyHolder.addProperty( prop, inferredData.getAttributeMember(), columns, inferredData.getDeclaringClass() );
|
||||||
binder.callAttributeBindersInSecondPass( prop );
|
binder.callAttributeBindersInSecondPass( prop );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ImplicitDiscriminatorStrategy resolveImplicitDiscriminatorStrategy(
|
||||||
|
AnyDiscriminatorImplicitValues anyDiscriminatorImplicitValues,
|
||||||
|
MetadataBuildingContext context) {
|
||||||
|
final AnyDiscriminatorImplicitValues.Strategy strategy = anyDiscriminatorImplicitValues.value();
|
||||||
|
|
||||||
|
if ( strategy == AnyDiscriminatorImplicitValues.Strategy.FULL_NAME ) {
|
||||||
|
return FullNameImplicitDiscriminatorStrategy.FULL_NAME_STRATEGY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( strategy == AnyDiscriminatorImplicitValues.Strategy.SHORT_NAME ) {
|
||||||
|
return ShortNameImplicitDiscriminatorStrategy.SHORT_NAME_STRATEGY;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert strategy == AnyDiscriminatorImplicitValues.Strategy.CUSTOM;
|
||||||
|
|
||||||
|
final Class<? extends ImplicitDiscriminatorStrategy> customStrategy = anyDiscriminatorImplicitValues.implementation();
|
||||||
|
|
||||||
|
if ( ImplicitDiscriminatorStrategy.class.equals( customStrategy ) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( FullNameImplicitDiscriminatorStrategy.class.equals( customStrategy ) ) {
|
||||||
|
return FullNameImplicitDiscriminatorStrategy.FULL_NAME_STRATEGY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ShortNameImplicitDiscriminatorStrategy.class.equals( customStrategy ) ) {
|
||||||
|
return ShortNameImplicitDiscriminatorStrategy.SHORT_NAME_STRATEGY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.getBootstrapContext().getCustomTypeProducer().produceBeanInstance( customStrategy );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import org.hibernate.AnnotationException;
|
||||||
import org.hibernate.AssertionFailure;
|
import org.hibernate.AssertionFailure;
|
||||||
import org.hibernate.FetchMode;
|
import org.hibernate.FetchMode;
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
|
import org.hibernate.annotations.AnyDiscriminatorImplicitValues;
|
||||||
import org.hibernate.annotations.AnyDiscriminatorValue;
|
import org.hibernate.annotations.AnyDiscriminatorValue;
|
||||||
import org.hibernate.annotations.AnyDiscriminatorValues;
|
import org.hibernate.annotations.AnyDiscriminatorValues;
|
||||||
import org.hibernate.annotations.Cascade;
|
import org.hibernate.annotations.Cascade;
|
||||||
|
@ -68,6 +69,7 @@ import jakarta.persistence.OneToOne;
|
||||||
import static jakarta.persistence.ConstraintMode.NO_CONSTRAINT;
|
import static jakarta.persistence.ConstraintMode.NO_CONSTRAINT;
|
||||||
import static jakarta.persistence.ConstraintMode.PROVIDER_DEFAULT;
|
import static jakarta.persistence.ConstraintMode.PROVIDER_DEFAULT;
|
||||||
import static org.hibernate.boot.model.internal.AnnotatedColumn.buildColumnOrFormulaFromAnnotation;
|
import static org.hibernate.boot.model.internal.AnnotatedColumn.buildColumnOrFormulaFromAnnotation;
|
||||||
|
import static org.hibernate.boot.model.internal.AnyBinder.resolveImplicitDiscriminatorStrategy;
|
||||||
import static org.hibernate.internal.util.StringHelper.isEmpty;
|
import static org.hibernate.internal.util.StringHelper.isEmpty;
|
||||||
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
|
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
|
||||||
import static org.hibernate.internal.util.StringHelper.qualifier;
|
import static org.hibernate.internal.util.StringHelper.qualifier;
|
||||||
|
@ -806,6 +808,12 @@ public class BinderHelper {
|
||||||
);
|
);
|
||||||
value.setDiscriminatorValueMappings( discriminatorValueMappings );
|
value.setDiscriminatorValueMappings( discriminatorValueMappings );
|
||||||
|
|
||||||
|
|
||||||
|
final AnyDiscriminatorImplicitValues anyDiscriminatorImplicitValues = property.getDirectAnnotationUsage( AnyDiscriminatorImplicitValues.class );
|
||||||
|
if ( anyDiscriminatorImplicitValues != null ) {
|
||||||
|
value.setImplicitDiscriminatorValueStrategy( resolveImplicitDiscriminatorStrategy( anyDiscriminatorImplicitValues, context ) );
|
||||||
|
}
|
||||||
|
|
||||||
final BasicValueBinder keyValueBinder = new BasicValueBinder( BasicValueBinder.Kind.ANY_KEY, context );
|
final BasicValueBinder keyValueBinder = new BasicValueBinder( BasicValueBinder.Kind.ANY_KEY, context );
|
||||||
final List<AnnotatedJoinColumn> columns = keyColumns.getJoinColumns();
|
final List<AnnotatedJoinColumn> columns = keyColumns.getJoinColumns();
|
||||||
assert columns.size() == 1;
|
assert columns.size() == 1;
|
||||||
|
|
|
@ -36,6 +36,10 @@ public interface HibernateAnnotations {
|
||||||
AnyDiscriminator.class,
|
AnyDiscriminator.class,
|
||||||
AnyDiscriminatorAnnotation.class
|
AnyDiscriminatorAnnotation.class
|
||||||
);
|
);
|
||||||
|
OrmAnnotationDescriptor<AnyDiscriminatorImplicitValues,AnyDiscriminatorImplicitValuesAnnotation> ANY_DISCRIMINATOR_IMPLICIT_VALUES = new OrmAnnotationDescriptor<>(
|
||||||
|
AnyDiscriminatorImplicitValues.class,
|
||||||
|
AnyDiscriminatorImplicitValuesAnnotation.class
|
||||||
|
);
|
||||||
OrmAnnotationDescriptor<AnyDiscriminatorValues,AnyDiscriminatorValuesAnnotation> ANY_DISCRIMINATOR_VALUES = new OrmAnnotationDescriptor<>(
|
OrmAnnotationDescriptor<AnyDiscriminatorValues,AnyDiscriminatorValuesAnnotation> ANY_DISCRIMINATOR_VALUES = new OrmAnnotationDescriptor<>(
|
||||||
AnyDiscriminatorValues.class,
|
AnyDiscriminatorValues.class,
|
||||||
AnyDiscriminatorValuesAnnotation.class
|
AnyDiscriminatorValuesAnnotation.class
|
||||||
|
|
|
@ -4,25 +4,22 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.boot.models.annotations.internal;
|
package org.hibernate.boot.models.annotations.internal;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.hibernate.annotations.AnyDiscriminator;
|
import org.hibernate.annotations.AnyDiscriminator;
|
||||||
import org.hibernate.models.spi.SourceModelBuildingContext;
|
import org.hibernate.models.spi.SourceModelBuildingContext;
|
||||||
import org.hibernate.type.AnyDiscriminatorValueStrategy;
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@SuppressWarnings({ "ClassExplicitlyAnnotation", "unused" })
|
@SuppressWarnings({ "ClassExplicitlyAnnotation", "unused" })
|
||||||
@jakarta.annotation.Generated("org.hibernate.orm.build.annotations.ClassGeneratorProcessor")
|
@jakarta.annotation.Generated("org.hibernate.orm.build.annotations.ClassGeneratorProcessor")
|
||||||
public class AnyDiscriminatorAnnotation implements AnyDiscriminator {
|
public class AnyDiscriminatorAnnotation implements AnyDiscriminator {
|
||||||
private jakarta.persistence.DiscriminatorType value;
|
private jakarta.persistence.DiscriminatorType value;
|
||||||
private AnyDiscriminatorValueStrategy valueStrategy;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used in creating dynamic annotation instances (e.g. from XML)
|
* Used in creating dynamic annotation instances (e.g. from XML)
|
||||||
*/
|
*/
|
||||||
public AnyDiscriminatorAnnotation(SourceModelBuildingContext modelContext) {
|
public AnyDiscriminatorAnnotation(SourceModelBuildingContext modelContext) {
|
||||||
this.value = jakarta.persistence.DiscriminatorType.STRING;
|
this.value = jakarta.persistence.DiscriminatorType.STRING;
|
||||||
this.valueStrategy = AnyDiscriminatorValueStrategy.AUTO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,7 +27,6 @@ public class AnyDiscriminatorAnnotation implements AnyDiscriminator {
|
||||||
*/
|
*/
|
||||||
public AnyDiscriminatorAnnotation(AnyDiscriminator annotation, SourceModelBuildingContext modelContext) {
|
public AnyDiscriminatorAnnotation(AnyDiscriminator annotation, SourceModelBuildingContext modelContext) {
|
||||||
this.value = annotation.value();
|
this.value = annotation.value();
|
||||||
this.valueStrategy = annotation.valueStrategy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,15 +49,4 @@ public class AnyDiscriminatorAnnotation implements AnyDiscriminator {
|
||||||
public void value(jakarta.persistence.DiscriminatorType value) {
|
public void value(jakarta.persistence.DiscriminatorType value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public AnyDiscriminatorValueStrategy valueStrategy() {
|
|
||||||
return valueStrategy;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void valueStrategy(AnyDiscriminatorValueStrategy valueStrategy) {
|
|
||||||
this.valueStrategy = valueStrategy;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.boot.models.annotations.internal;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.AnyDiscriminatorImplicitValues;
|
||||||
|
import org.hibernate.metamodel.spi.ImplicitDiscriminatorStrategy;
|
||||||
|
import org.hibernate.models.spi.SourceModelBuildingContext;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@SuppressWarnings({ "ClassExplicitlyAnnotation", "unused" })
|
||||||
|
@jakarta.annotation.Generated("org.hibernate.orm.build.annotations.ClassGeneratorProcessor")
|
||||||
|
public class AnyDiscriminatorImplicitValuesAnnotation implements AnyDiscriminatorImplicitValues {
|
||||||
|
private AnyDiscriminatorImplicitValues.Strategy value;
|
||||||
|
private Class<? extends ImplicitDiscriminatorStrategy> implementation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used in creating dynamic annotation instances (e.g. from XML)
|
||||||
|
*/
|
||||||
|
public AnyDiscriminatorImplicitValuesAnnotation(SourceModelBuildingContext modelContext) {
|
||||||
|
this.value = Strategy.CUSTOM;
|
||||||
|
this.implementation = ImplicitDiscriminatorStrategy.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used in creating annotation instances from JDK variant
|
||||||
|
*/
|
||||||
|
public AnyDiscriminatorImplicitValuesAnnotation(AnyDiscriminatorImplicitValues annotation, SourceModelBuildingContext modelContext) {
|
||||||
|
this.value = annotation.value();
|
||||||
|
this.implementation = annotation.implementation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used in creating annotation instances from Jandex variant
|
||||||
|
*/
|
||||||
|
public AnyDiscriminatorImplicitValuesAnnotation(Map<String, Object> attributeValues, SourceModelBuildingContext modelContext) {
|
||||||
|
this.value = (Strategy) attributeValues.get( "value" );
|
||||||
|
//noinspection unchecked
|
||||||
|
this.implementation = (Class<? extends ImplicitDiscriminatorStrategy>) attributeValues.get( "implementation" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends Annotation> annotationType() {
|
||||||
|
return AnyDiscriminatorImplicitValues.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Strategy value() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void value(Strategy value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends ImplicitDiscriminatorStrategy> implementation() {
|
||||||
|
return implementation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void implementation(Class<? extends ImplicitDiscriminatorStrategy> implementation) {
|
||||||
|
this.implementation = implementation;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,19 +4,19 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.mapping;
|
package org.hibernate.mapping;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
import org.hibernate.Incubating;
|
import org.hibernate.Incubating;
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||||
import org.hibernate.type.AnyDiscriminatorValueStrategy;
|
import org.hibernate.metamodel.spi.ImplicitDiscriminatorStrategy;
|
||||||
import org.hibernate.type.AnyType;
|
import org.hibernate.type.AnyType;
|
||||||
import org.hibernate.type.Type;
|
|
||||||
import org.hibernate.type.MappingContext;
|
import org.hibernate.type.MappingContext;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mapping model object representing a {@linkplain org.hibernate.annotations.Any polymorphic association}
|
* A mapping model object representing a {@linkplain org.hibernate.annotations.Any polymorphic association}
|
||||||
|
@ -35,7 +35,7 @@ public class Any extends SimpleValue {
|
||||||
|
|
||||||
// common
|
// common
|
||||||
private Map<Object,String> metaValueToEntityNameMap;
|
private Map<Object,String> metaValueToEntityNameMap;
|
||||||
private AnyDiscriminatorValueStrategy discriminatorValueStrategy = AnyDiscriminatorValueStrategy.AUTO;
|
private ImplicitDiscriminatorStrategy implicitValueStrategy;
|
||||||
private boolean lazy = true;
|
private boolean lazy = true;
|
||||||
|
|
||||||
private AnyType resolvedType;
|
private AnyType resolvedType;
|
||||||
|
@ -75,7 +75,7 @@ public class Any extends SimpleValue {
|
||||||
this.metaValueToEntityNameMap = original.metaValueToEntityNameMap == null
|
this.metaValueToEntityNameMap = original.metaValueToEntityNameMap == null
|
||||||
? null
|
? null
|
||||||
: new HashMap<>(original.metaValueToEntityNameMap);
|
: new HashMap<>(original.metaValueToEntityNameMap);
|
||||||
this.discriminatorValueStrategy = original.discriminatorValueStrategy;
|
this.implicitValueStrategy = original.implicitValueStrategy;
|
||||||
this.lazy = original.lazy;
|
this.lazy = original.lazy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,28 +131,6 @@ public class Any extends SimpleValue {
|
||||||
this.keyMapping.setTypeName( identifierType );
|
this.keyMapping.setTypeName( identifierType );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Current strategy for interpreting {@linkplain org.hibernate.annotations.AnyDiscriminatorValue} definitions,
|
|
||||||
* especially in terms of implicit, explicit and potentially missing values.
|
|
||||||
*
|
|
||||||
* @since 7.0
|
|
||||||
*/
|
|
||||||
@Incubating
|
|
||||||
public AnyDiscriminatorValueStrategy getDiscriminatorValueStrategy() {
|
|
||||||
return discriminatorValueStrategy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the strategy
|
|
||||||
*
|
|
||||||
* @see #getDiscriminatorValueStrategy
|
|
||||||
* @since 7.0
|
|
||||||
*/
|
|
||||||
@Incubating
|
|
||||||
public void setDiscriminatorValueStrategy(AnyDiscriminatorValueStrategy discriminatorValueStrategy) {
|
|
||||||
this.discriminatorValueStrategy = discriminatorValueStrategy;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AnyType getType() throws MappingException {
|
public AnyType getType() throws MappingException {
|
||||||
if ( resolvedType == null ) {
|
if ( resolvedType == null ) {
|
||||||
|
@ -175,8 +153,8 @@ public class Any extends SimpleValue {
|
||||||
resolvedType = MappingHelper.anyMapping(
|
resolvedType = MappingHelper.anyMapping(
|
||||||
discriminatorType,
|
discriminatorType,
|
||||||
identifierType,
|
identifierType,
|
||||||
discriminatorValueStrategy,
|
|
||||||
metaValueToEntityNameMap,
|
metaValueToEntityNameMap,
|
||||||
|
implicitValueStrategy,
|
||||||
isLazy(),
|
isLazy(),
|
||||||
getBuildingContext()
|
getBuildingContext()
|
||||||
);
|
);
|
||||||
|
@ -242,6 +220,19 @@ public class Any extends SimpleValue {
|
||||||
this.metaValueToEntityNameMap = metaValueToEntityNameMap;
|
this.metaValueToEntityNameMap = metaValueToEntityNameMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the strategy for dealing with discriminator mappings which are not explicitly defined by
|
||||||
|
* {@linkplain org.hibernate.annotations.AnyDiscriminatorValue}.
|
||||||
|
*
|
||||||
|
* @apiNote {@code null} indicates to not allow implicit mappings.
|
||||||
|
*
|
||||||
|
* @since 7.0
|
||||||
|
*/
|
||||||
|
@Incubating
|
||||||
|
public void setImplicitDiscriminatorValueStrategy(ImplicitDiscriminatorStrategy implicitValueStrategy) {
|
||||||
|
this.implicitValueStrategy = implicitValueStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isLazy() {
|
public boolean isLazy() {
|
||||||
return lazy;
|
return lazy;
|
||||||
}
|
}
|
||||||
|
@ -334,7 +325,6 @@ public class Any extends SimpleValue {
|
||||||
public static class MetaValue extends SimpleValue {
|
public static class MetaValue extends SimpleValue {
|
||||||
private String typeName;
|
private String typeName;
|
||||||
private String columnName;
|
private String columnName;
|
||||||
private AnyDiscriminatorValueStrategy valueStrategy;
|
|
||||||
|
|
||||||
private final Consumer<Selectable> selectableConsumer;
|
private final Consumer<Selectable> selectableConsumer;
|
||||||
|
|
||||||
|
@ -427,10 +417,6 @@ public class Any extends SimpleValue {
|
||||||
return columnName != null
|
return columnName != null
|
||||||
&& getType().getColumnSpan( mappingContext ) == 1;
|
&& getType().getColumnSpan( mappingContext ) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AnyDiscriminatorValueStrategy getValueStrategy() {
|
|
||||||
return valueStrategy;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class KeyValue extends SimpleValue {
|
public static class KeyValue extends SimpleValue {
|
||||||
|
|
|
@ -18,11 +18,11 @@ import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||||
import org.hibernate.boot.spi.MetadataImplementor;
|
import org.hibernate.boot.spi.MetadataImplementor;
|
||||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||||
|
import org.hibernate.metamodel.spi.ImplicitDiscriminatorStrategy;
|
||||||
import org.hibernate.resource.beans.internal.FallbackBeanInstanceProducer;
|
import org.hibernate.resource.beans.internal.FallbackBeanInstanceProducer;
|
||||||
import org.hibernate.resource.beans.spi.ManagedBean;
|
import org.hibernate.resource.beans.spi.ManagedBean;
|
||||||
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
|
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
|
||||||
import org.hibernate.resource.beans.spi.ProvidedInstanceManagedBeanImpl;
|
import org.hibernate.resource.beans.spi.ProvidedInstanceManagedBeanImpl;
|
||||||
import org.hibernate.type.AnyDiscriminatorValueStrategy;
|
|
||||||
import org.hibernate.type.AnyType;
|
import org.hibernate.type.AnyType;
|
||||||
import org.hibernate.type.CollectionType;
|
import org.hibernate.type.CollectionType;
|
||||||
import org.hibernate.type.CustomCollectionType;
|
import org.hibernate.type.CustomCollectionType;
|
||||||
|
@ -129,17 +129,24 @@ public final class MappingHelper {
|
||||||
Map<Object, String> explicitValeMappings,
|
Map<Object, String> explicitValeMappings,
|
||||||
boolean lazy,
|
boolean lazy,
|
||||||
MetadataBuildingContext buildingContext) {
|
MetadataBuildingContext buildingContext) {
|
||||||
return anyMapping( discriminatorType, identifierType, AnyDiscriminatorValueStrategy.AUTO, explicitValeMappings, lazy, buildingContext );
|
return anyMapping(
|
||||||
|
discriminatorType,
|
||||||
|
identifierType,
|
||||||
|
explicitValeMappings,
|
||||||
|
null,
|
||||||
|
lazy,
|
||||||
|
buildingContext
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AnyType anyMapping(
|
public static AnyType anyMapping(
|
||||||
Type discriminatorType,
|
Type discriminatorType,
|
||||||
Type identifierType,
|
Type identifierType,
|
||||||
AnyDiscriminatorValueStrategy discriminatorValueStrategy,
|
|
||||||
Map<Object, String> explicitValeMappings,
|
Map<Object, String> explicitValeMappings,
|
||||||
|
ImplicitDiscriminatorStrategy implicitValueStrategy,
|
||||||
boolean lazy,
|
boolean lazy,
|
||||||
MetadataBuildingContext buildingContext) {
|
MetadataBuildingContext buildingContext) {
|
||||||
final MetaType metaType = new MetaType( discriminatorType, discriminatorValueStrategy, explicitValeMappings );
|
final MetaType metaType = new MetaType( discriminatorType, implicitValueStrategy, explicitValeMappings );
|
||||||
return new AnyType( buildingContext.getBootstrapContext().getTypeConfiguration(), metaType, identifierType, lazy );
|
return new AnyType( buildingContext.getBootstrapContext().getTypeConfiguration(), metaType, identifierType, lazy );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.metamodel.internal;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
|
import org.hibernate.metamodel.spi.ImplicitDiscriminatorStrategy;
|
||||||
|
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ImplicitDiscriminatorStrategy implementation using entity {@linkplain EntityMappingType#getEntityName() full-names}.
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class FullNameImplicitDiscriminatorStrategy implements ImplicitDiscriminatorStrategy {
|
||||||
|
public static final FullNameImplicitDiscriminatorStrategy FULL_NAME_STRATEGY = new FullNameImplicitDiscriminatorStrategy();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object toDiscriminatorValue(EntityMappingType entityMapping, NavigableRole discriminatorRole, MappingMetamodelImplementor mappingModel) {
|
||||||
|
return entityMapping.getEntityName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityMappingType toEntityMapping(Object discriminatorValue, NavigableRole discriminatorRole, MappingMetamodelImplementor mappingModel) {
|
||||||
|
if ( discriminatorValue instanceof String assumedEntityName ) {
|
||||||
|
final EntityPersister persister = mappingModel.findEntityDescriptor( assumedEntityName );
|
||||||
|
|
||||||
|
if ( persister != null ) {
|
||||||
|
return persister;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new HibernateException( "Cannot interpret discriminator value (" + discriminatorRole + ") : " + discriminatorValue );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.metamodel.internal;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
|
import org.hibernate.metamodel.spi.ImplicitDiscriminatorStrategy;
|
||||||
|
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ImplicitDiscriminatorStrategy implementation using entity {@linkplain EntityMappingType#getEntityName() full-names}.
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class ShortNameImplicitDiscriminatorStrategy implements ImplicitDiscriminatorStrategy {
|
||||||
|
public static final ShortNameImplicitDiscriminatorStrategy SHORT_NAME_STRATEGY = new ShortNameImplicitDiscriminatorStrategy();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object toDiscriminatorValue(EntityMappingType entityMapping, NavigableRole discriminatorRole, MappingMetamodelImplementor mappingModel) {
|
||||||
|
return entityMapping.getImportedName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityMappingType toEntityMapping(Object discriminatorValue, NavigableRole discriminatorRole, MappingMetamodelImplementor mappingModel) {
|
||||||
|
if ( discriminatorValue instanceof String assumedEntityName ) {
|
||||||
|
final String importedName = mappingModel.getImportedName( assumedEntityName );
|
||||||
|
final EntityMappingType entityMapping = mappingModel.findEntityDescriptor( importedName );
|
||||||
|
if ( entityMapping != null ) {
|
||||||
|
return entityMapping;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new HibernateException( "Cannot interpret discriminator value (" + discriminatorRole + ") : " + discriminatorValue );
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,9 +4,7 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.metamodel.mapping;
|
package org.hibernate.metamodel.mapping;
|
||||||
|
|
||||||
import org.hibernate.Incubating;
|
|
||||||
import org.hibernate.metamodel.RepresentationMode;
|
import org.hibernate.metamodel.RepresentationMode;
|
||||||
import org.hibernate.type.AnyDiscriminatorValueStrategy;
|
|
||||||
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
|
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
|
||||||
import org.hibernate.type.descriptor.java.JavaType;
|
import org.hibernate.type.descriptor.java.JavaType;
|
||||||
|
|
||||||
|
@ -31,9 +29,6 @@ public abstract class DiscriminatorConverter<O,R> implements BasicValueConverter
|
||||||
this.relationalJavaType = relationalJavaType;
|
this.relationalJavaType = relationalJavaType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Incubating
|
|
||||||
public abstract AnyDiscriminatorValueStrategy getValueStrategy();
|
|
||||||
|
|
||||||
public String getDiscriminatorName() {
|
public String getDiscriminatorName() {
|
||||||
return discriminatorName;
|
return discriminatorName;
|
||||||
}
|
}
|
||||||
|
@ -90,7 +85,7 @@ public abstract class DiscriminatorConverter<O,R> implements BasicValueConverter
|
||||||
return (R) discriminatorValueDetails.getValue();
|
return (R) discriminatorValueDetails.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relationalForm);
|
public abstract DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relationalValue);
|
||||||
|
|
||||||
public abstract DiscriminatorValueDetails getDetailsForEntityName(String entityName);
|
public abstract DiscriminatorValueDetails getDetailsForEntityName(String entityName);
|
||||||
|
|
||||||
|
@ -101,5 +96,8 @@ public abstract class DiscriminatorConverter<O,R> implements BasicValueConverter
|
||||||
|
|
||||||
public abstract void forEachValueDetail(Consumer<DiscriminatorValueDetails> consumer);
|
public abstract void forEachValueDetail(Consumer<DiscriminatorValueDetails> consumer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find and return the first DiscriminatorValueDetails which matches the given {@code handler}
|
||||||
|
*/
|
||||||
public abstract <X> X fromValueDetails(Function<DiscriminatorValueDetails,X> handler);
|
public abstract <X> X fromValueDetails(Function<DiscriminatorValueDetails,X> handler);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import org.hibernate.HibernateException;
|
||||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||||
import org.hibernate.metamodel.mapping.internal.EmbeddableDiscriminatorValueDetailsImpl;
|
import org.hibernate.metamodel.mapping.internal.EmbeddableDiscriminatorValueDetailsImpl;
|
||||||
import org.hibernate.service.ServiceRegistry;
|
import org.hibernate.service.ServiceRegistry;
|
||||||
import org.hibernate.type.AnyDiscriminatorValueStrategy;
|
|
||||||
import org.hibernate.type.BasicType;
|
import org.hibernate.type.BasicType;
|
||||||
import org.hibernate.type.descriptor.java.JavaType;
|
import org.hibernate.type.descriptor.java.JavaType;
|
||||||
|
|
||||||
|
@ -66,12 +65,6 @@ public class EmbeddableDiscriminatorConverter<O, R> extends DiscriminatorConvert
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public AnyDiscriminatorValueStrategy getValueStrategy() {
|
|
||||||
// discriminators for embeddables are always explicit
|
|
||||||
return AnyDiscriminatorValueStrategy.EXPLICIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public O toDomainValue(R relationalForm) {
|
public O toDomainValue(R relationalForm) {
|
||||||
assert relationalForm == null || getRelationalJavaType().isInstance( relationalForm );
|
assert relationalForm == null || getRelationalJavaType().isInstance( relationalForm );
|
||||||
|
@ -86,13 +79,13 @@ public class EmbeddableDiscriminatorConverter<O, R> extends DiscriminatorConvert
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EmbeddableDiscriminatorValueDetailsImpl getDetailsForDiscriminatorValue(Object value) {
|
public EmbeddableDiscriminatorValueDetailsImpl getDetailsForDiscriminatorValue(Object relationalValue) {
|
||||||
final EmbeddableDiscriminatorValueDetailsImpl valueMatch = discriminatorValueToDetailsMap.get( value );
|
final EmbeddableDiscriminatorValueDetailsImpl valueMatch = discriminatorValueToDetailsMap.get( relationalValue );
|
||||||
if ( valueMatch != null ) {
|
if ( valueMatch != null ) {
|
||||||
return valueMatch;
|
return valueMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new HibernateException( "Unrecognized discriminator value: " + value );
|
throw new HibernateException( "Unrecognized discriminator value: " + relationalValue );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -462,6 +462,10 @@ public interface EntityMappingType
|
||||||
|
|
||||||
void visitConstraintOrderedTables(ConstraintOrderedTableConsumer consumer);
|
void visitConstraintOrderedTables(ConstraintOrderedTableConsumer consumer);
|
||||||
|
|
||||||
|
default String getImportedName() {
|
||||||
|
return getEntityPersister().getImportedName();
|
||||||
|
}
|
||||||
|
|
||||||
interface ConstraintOrderedTableConsumer {
|
interface ConstraintOrderedTableConsumer {
|
||||||
void consume(String tableExpression, Supplier<Consumer<SelectableConsumer>> tableKeyColumnVisitationSupplier);
|
void consume(String tableExpression, Supplier<Consumer<SelectableConsumer>> tableKeyColumnVisitationSupplier);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.metamodel.mapping.internal;
|
package org.hibernate.metamodel.mapping.internal;
|
||||||
|
|
||||||
import org.hibernate.AssertionFailure;
|
|
||||||
import org.hibernate.cache.MutableCacheKeyBuilder;
|
import org.hibernate.cache.MutableCacheKeyBuilder;
|
||||||
import org.hibernate.engine.FetchStyle;
|
import org.hibernate.engine.FetchStyle;
|
||||||
import org.hibernate.engine.FetchTiming;
|
import org.hibernate.engine.FetchTiming;
|
||||||
|
@ -20,6 +19,7 @@ import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.MappingType;
|
import org.hibernate.metamodel.mapping.MappingType;
|
||||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
|
import org.hibernate.metamodel.spi.ImplicitDiscriminatorStrategy;
|
||||||
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
|
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
|
||||||
import org.hibernate.spi.NavigablePath;
|
import org.hibernate.spi.NavigablePath;
|
||||||
import org.hibernate.sql.ast.spi.FromClauseAccess;
|
import org.hibernate.sql.ast.spi.FromClauseAccess;
|
||||||
|
@ -35,7 +35,6 @@ import org.hibernate.sql.results.graph.FetchOptions;
|
||||||
import org.hibernate.sql.results.graph.FetchParent;
|
import org.hibernate.sql.results.graph.FetchParent;
|
||||||
import org.hibernate.sql.results.graph.basic.BasicFetch;
|
import org.hibernate.sql.results.graph.basic.BasicFetch;
|
||||||
import org.hibernate.sql.results.graph.basic.BasicResult;
|
import org.hibernate.sql.results.graph.basic.BasicResult;
|
||||||
import org.hibernate.type.AnyDiscriminatorValueStrategy;
|
|
||||||
import org.hibernate.type.BasicType;
|
import org.hibernate.type.BasicType;
|
||||||
import org.hibernate.type.descriptor.java.ClassJavaType;
|
import org.hibernate.type.descriptor.java.ClassJavaType;
|
||||||
import org.hibernate.type.descriptor.java.JavaType;
|
import org.hibernate.type.descriptor.java.JavaType;
|
||||||
|
@ -84,7 +83,7 @@ public class AnyDiscriminatorPart implements DiscriminatorMapping, FetchOptions
|
||||||
boolean partitioned,
|
boolean partitioned,
|
||||||
BasicType<?> underlyingJdbcMapping,
|
BasicType<?> underlyingJdbcMapping,
|
||||||
Map<Object,String> valueToEntityNameMap,
|
Map<Object,String> valueToEntityNameMap,
|
||||||
AnyDiscriminatorValueStrategy valueStrategy,
|
ImplicitDiscriminatorStrategy implicitValueStrategy,
|
||||||
MappingMetamodelImplementor mappingMetamodel) {
|
MappingMetamodelImplementor mappingMetamodel) {
|
||||||
this.navigableRole = partRole;
|
this.navigableRole = partRole;
|
||||||
this.declaringType = declaringType;
|
this.declaringType = declaringType;
|
||||||
|
@ -105,7 +104,7 @@ public class AnyDiscriminatorPart implements DiscriminatorMapping, FetchOptions
|
||||||
partRole,
|
partRole,
|
||||||
underlyingJdbcMapping,
|
underlyingJdbcMapping,
|
||||||
valueToEntityNameMap,
|
valueToEntityNameMap,
|
||||||
valueStrategy,
|
implicitValueStrategy,
|
||||||
mappingMetamodel
|
mappingMetamodel
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -114,41 +113,16 @@ public class AnyDiscriminatorPart implements DiscriminatorMapping, FetchOptions
|
||||||
NavigableRole partRole,
|
NavigableRole partRole,
|
||||||
BasicType<?> underlyingJdbcMapping,
|
BasicType<?> underlyingJdbcMapping,
|
||||||
Map<Object, String> valueToEntityNameMap,
|
Map<Object, String> valueToEntityNameMap,
|
||||||
AnyDiscriminatorValueStrategy valueStrategy,
|
ImplicitDiscriminatorStrategy implicitValueStrategy,
|
||||||
MappingMetamodelImplementor mappingMetamodel) {
|
MappingMetamodelImplementor mappingMetamodel) {
|
||||||
if ( valueStrategy == AnyDiscriminatorValueStrategy.AUTO ) {
|
return new UnifiedAnyDiscriminatorConverter<>(
|
||||||
if ( valueToEntityNameMap == null || valueToEntityNameMap.isEmpty() ) {
|
|
||||||
valueStrategy = AnyDiscriminatorValueStrategy.IMPLICIT;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
valueStrategy = AnyDiscriminatorValueStrategy.EXPLICIT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return switch ( valueStrategy ) {
|
|
||||||
case AUTO -> throw new AssertionFailure( "Not expecting AUTO" );
|
|
||||||
case MIXED -> new MixedDiscriminatorConverter<>(
|
|
||||||
partRole,
|
partRole,
|
||||||
ClassJavaType.INSTANCE,
|
ClassJavaType.INSTANCE,
|
||||||
underlyingJdbcMapping.getJavaTypeDescriptor(),
|
underlyingJdbcMapping.getJavaTypeDescriptor(),
|
||||||
valueToEntityNameMap,
|
valueToEntityNameMap,
|
||||||
|
implicitValueStrategy,
|
||||||
mappingMetamodel
|
mappingMetamodel
|
||||||
);
|
);
|
||||||
case EXPLICIT -> new ExplicitDiscriminatorConverter<>(
|
|
||||||
partRole,
|
|
||||||
ClassJavaType.INSTANCE,
|
|
||||||
underlyingJdbcMapping.getJavaTypeDescriptor(),
|
|
||||||
valueToEntityNameMap,
|
|
||||||
mappingMetamodel
|
|
||||||
);
|
|
||||||
case IMPLICIT -> new ImplicitDiscriminatorConverter<>(
|
|
||||||
partRole,
|
|
||||||
ClassJavaType.INSTANCE,
|
|
||||||
underlyingJdbcMapping.getJavaTypeDescriptor(),
|
|
||||||
valueToEntityNameMap,
|
|
||||||
mappingMetamodel
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DiscriminatorConverter<?,?> getValueConverter() {
|
public DiscriminatorConverter<?,?> getValueConverter() {
|
||||||
|
|
|
@ -89,7 +89,7 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
|
||||||
bootValueMapping.isPartitionKey(),
|
bootValueMapping.isPartitionKey(),
|
||||||
(BasicType<?>) metaType.getBaseType(),
|
(BasicType<?>) metaType.getBaseType(),
|
||||||
metaType.getDiscriminatorValuesToEntityNameMap(),
|
metaType.getDiscriminatorValuesToEntityNameMap(),
|
||||||
metaType.getValueStrategy(),
|
metaType.getImplicitValueStrategy(),
|
||||||
creationProcess.getCreationContext().getSessionFactory().getMappingMetamodel()
|
creationProcess.getCreationContext().getSessionFactory().getMappingMetamodel()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,144 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
|
||||||
* Copyright Red Hat Inc. and Hibernate Authors
|
|
||||||
*/
|
|
||||||
package org.hibernate.metamodel.mapping.internal;
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.MappingException;
|
|
||||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
|
||||||
import org.hibernate.metamodel.mapping.DiscriminatorConverter;
|
|
||||||
import org.hibernate.metamodel.mapping.DiscriminatorValueDetails;
|
|
||||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
|
||||||
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
|
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
|
||||||
import org.hibernate.type.AnyDiscriminatorValueStrategy;
|
|
||||||
import org.hibernate.type.descriptor.java.CharacterJavaType;
|
|
||||||
import org.hibernate.type.descriptor.java.JavaType;
|
|
||||||
import org.hibernate.type.descriptor.java.StringJavaType;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import static java.util.Locale.ROOT;
|
|
||||||
import static org.hibernate.persister.entity.DiscriminatorHelper.NOT_NULL_DISCRIMINATOR;
|
|
||||||
import static org.hibernate.persister.entity.DiscriminatorHelper.NULL_DISCRIMINATOR;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Steve Ebersole
|
|
||||||
*/
|
|
||||||
public class ExplicitDiscriminatorConverter<O,R> extends DiscriminatorConverter<O, R> {
|
|
||||||
private final NavigableRole discriminatorRole;
|
|
||||||
private final Map<Object, DiscriminatorValueDetails> detailsByValue;
|
|
||||||
private final Map<String,DiscriminatorValueDetails> detailsByEntityName;
|
|
||||||
|
|
||||||
public ExplicitDiscriminatorConverter(
|
|
||||||
NavigableRole discriminatorRole,
|
|
||||||
JavaType<O> domainJavaType,
|
|
||||||
JavaType<R> relationalJavaType,
|
|
||||||
Map<Object, String> explicitValueMappings,
|
|
||||||
MappingMetamodelImplementor mappingMetamodel) {
|
|
||||||
super( discriminatorRole.getFullPath(), domainJavaType, relationalJavaType );
|
|
||||||
this.discriminatorRole = discriminatorRole;
|
|
||||||
|
|
||||||
if ( CollectionHelper.isEmpty( explicitValueMappings ) ) {
|
|
||||||
throw new MappingException( String.format(
|
|
||||||
ROOT,
|
|
||||||
"No explicit ANY discriminator mappings (%s)",
|
|
||||||
discriminatorRole.getFullPath()
|
|
||||||
) );
|
|
||||||
}
|
|
||||||
|
|
||||||
this.detailsByValue = CollectionHelper.concurrentMap( explicitValueMappings.size() );
|
|
||||||
this.detailsByEntityName = CollectionHelper.concurrentMap( explicitValueMappings.size() );
|
|
||||||
|
|
||||||
explicitValueMappings.forEach( (value, entityName) -> {
|
|
||||||
final EntityPersister entityDescriptor = mappingMetamodel.getEntityDescriptor( entityName );
|
|
||||||
final DiscriminatorValueDetails details = new DiscriminatorValueDetailsImpl( value, entityDescriptor );
|
|
||||||
detailsByValue.put( value, details );
|
|
||||||
detailsByEntityName.put( entityDescriptor.getEntityName(), details );
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AnyDiscriminatorValueStrategy getValueStrategy() {
|
|
||||||
return AnyDiscriminatorValueStrategy.EXPLICIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<Object, DiscriminatorValueDetails> getDetailsByValue() {
|
|
||||||
return detailsByValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, DiscriminatorValueDetails> getDetailsByEntityName() {
|
|
||||||
return detailsByEntityName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relationalForm) {
|
|
||||||
if ( relationalForm == null ) {
|
|
||||||
return detailsByValue.get( NULL_DISCRIMINATOR );
|
|
||||||
}
|
|
||||||
|
|
||||||
final DiscriminatorValueDetails existing = detailsByValue.get( relationalForm );
|
|
||||||
if ( existing != null ) {
|
|
||||||
// an explicit or previously-resolved mapping
|
|
||||||
return existing;
|
|
||||||
}
|
|
||||||
|
|
||||||
final DiscriminatorValueDetails notNullMatch = detailsByValue.get( NOT_NULL_DISCRIMINATOR );
|
|
||||||
if ( notNullMatch != null ) {
|
|
||||||
return notNullMatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( relationalForm.getClass().isEnum() ) {
|
|
||||||
final Object enumValue;
|
|
||||||
if ( getRelationalJavaType() instanceof StringJavaType ) {
|
|
||||||
enumValue = ( (Enum<?>) relationalForm ).name();
|
|
||||||
}
|
|
||||||
else if ( getRelationalJavaType() instanceof CharacterJavaType ) {
|
|
||||||
enumValue = ( (Enum<?>) relationalForm ).name().charAt( 0 );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
enumValue = ( (Enum<?>) relationalForm ).ordinal();
|
|
||||||
}
|
|
||||||
final DiscriminatorValueDetails enumMatch = detailsByValue.get( enumValue );
|
|
||||||
if ( enumMatch != null ) {
|
|
||||||
return enumMatch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new HibernateException( String.format(
|
|
||||||
ROOT,
|
|
||||||
"Unknown discriminator value (%s) : %s",
|
|
||||||
discriminatorRole,
|
|
||||||
relationalForm
|
|
||||||
) );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DiscriminatorValueDetails getDetailsForEntityName(String entityName) {
|
|
||||||
final DiscriminatorValueDetails valueDetails = detailsByEntityName.get( entityName );
|
|
||||||
if ( valueDetails != null) {
|
|
||||||
return valueDetails;
|
|
||||||
}
|
|
||||||
throw new HibernateException( "Entity not explicitly mapped for ANY discriminator (" + discriminatorRole + ") : " + entityName );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void forEachValueDetail(Consumer<DiscriminatorValueDetails> consumer) {
|
|
||||||
detailsByEntityName.forEach( (value, detail) -> consumer.accept( detail ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <X> X fromValueDetails(Function<DiscriminatorValueDetails, X> handler) {
|
|
||||||
for ( DiscriminatorValueDetails detail : detailsByEntityName.values() ) {
|
|
||||||
final X result = handler.apply( detail );
|
|
||||||
if ( result != null ) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,121 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
|
||||||
* Copyright Red Hat Inc. and Hibernate Authors
|
|
||||||
*/
|
|
||||||
package org.hibernate.metamodel.mapping.internal;
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.MappingException;
|
|
||||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
|
||||||
import org.hibernate.metamodel.mapping.DiscriminatorConverter;
|
|
||||||
import org.hibernate.metamodel.mapping.DiscriminatorValueDetails;
|
|
||||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
|
||||||
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
|
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
|
||||||
import org.hibernate.type.AnyDiscriminatorValueStrategy;
|
|
||||||
import org.hibernate.type.descriptor.java.JavaType;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import static java.util.Locale.ROOT;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Steve Ebersole
|
|
||||||
*/
|
|
||||||
public class ImplicitDiscriminatorConverter<O,R> extends DiscriminatorConverter<O,R> {
|
|
||||||
private final NavigableRole discriminatorRole;
|
|
||||||
private final MappingMetamodelImplementor mappingMetamodel;
|
|
||||||
private final Map<Object, DiscriminatorValueDetails> detailsByValue;
|
|
||||||
private final Map<String,DiscriminatorValueDetails> detailsByEntityName;
|
|
||||||
|
|
||||||
public ImplicitDiscriminatorConverter(
|
|
||||||
NavigableRole discriminatorRole,
|
|
||||||
JavaType<O> domainJavaType,
|
|
||||||
JavaType<R> relationalJavaType,
|
|
||||||
Map<Object,String> explicitValueMappings,
|
|
||||||
MappingMetamodelImplementor mappingMetamodel) {
|
|
||||||
super( discriminatorRole.getFullPath(), domainJavaType, relationalJavaType );
|
|
||||||
this.discriminatorRole = discriminatorRole;
|
|
||||||
this.mappingMetamodel = mappingMetamodel;
|
|
||||||
|
|
||||||
if ( CollectionHelper.isNotEmpty( explicitValueMappings ) ) {
|
|
||||||
throw new MappingException( String.format(
|
|
||||||
ROOT,
|
|
||||||
"Encountered explicit ANY discriminator mappings (%s)",
|
|
||||||
discriminatorRole.getFullPath()
|
|
||||||
) );
|
|
||||||
}
|
|
||||||
|
|
||||||
this.detailsByValue = CollectionHelper.concurrentMap( 8 );
|
|
||||||
this.detailsByEntityName = CollectionHelper.concurrentMap( 8 );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AnyDiscriminatorValueStrategy getValueStrategy() {
|
|
||||||
return AnyDiscriminatorValueStrategy.IMPLICIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<Object, DiscriminatorValueDetails> getDetailsByValue() {
|
|
||||||
return detailsByValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, DiscriminatorValueDetails> getDetailsByEntityName() {
|
|
||||||
return detailsByEntityName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object value) {
|
|
||||||
if ( value instanceof String incoming ) {
|
|
||||||
final DiscriminatorValueDetails existingDetails = detailsByValue.get( incoming );
|
|
||||||
if ( existingDetails != null ) {
|
|
||||||
return existingDetails;
|
|
||||||
}
|
|
||||||
final EntityPersister persister = mappingMetamodel.findEntityDescriptor( incoming );
|
|
||||||
if ( persister != null ) {
|
|
||||||
return register( incoming, persister );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new HibernateException( String.format(
|
|
||||||
ROOT,
|
|
||||||
"Unrecognized discriminator value (%s): %s",
|
|
||||||
discriminatorRole.getFullPath(),
|
|
||||||
value
|
|
||||||
) );
|
|
||||||
}
|
|
||||||
|
|
||||||
private DiscriminatorValueDetails register(Object value, EntityPersister entityDescriptor) {
|
|
||||||
final DiscriminatorValueDetails details = new DiscriminatorValueDetailsImpl( value, entityDescriptor );
|
|
||||||
detailsByValue.put( value, details );
|
|
||||||
detailsByEntityName.put( entityDescriptor.getEntityName(), details );
|
|
||||||
return details;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DiscriminatorValueDetails getDetailsForEntityName(String entityName) {
|
|
||||||
final DiscriminatorValueDetails existingDetails = detailsByEntityName.get( entityName );
|
|
||||||
if ( existingDetails != null ) {
|
|
||||||
return existingDetails;
|
|
||||||
}
|
|
||||||
final EntityPersister persister = mappingMetamodel.findEntityDescriptor( entityName );
|
|
||||||
if ( persister!= null ) {
|
|
||||||
return register( persister.getEntityName(), persister );
|
|
||||||
}
|
|
||||||
throw new HibernateException( String.format(
|
|
||||||
ROOT,
|
|
||||||
"Unrecognized entity name (%s): %s",
|
|
||||||
discriminatorRole.getFullPath(),
|
|
||||||
entityName
|
|
||||||
) );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void forEachValueDetail(Consumer<DiscriminatorValueDetails> consumer) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <X> X fromValueDetails(Function<DiscriminatorValueDetails,X> handler) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,12 +6,14 @@ package org.hibernate.metamodel.mapping.internal;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||||
|
import org.hibernate.metamodel.internal.FullNameImplicitDiscriminatorStrategy;
|
||||||
import org.hibernate.metamodel.mapping.DiscriminatorConverter;
|
import org.hibernate.metamodel.mapping.DiscriminatorConverter;
|
||||||
import org.hibernate.metamodel.mapping.DiscriminatorValueDetails;
|
import org.hibernate.metamodel.mapping.DiscriminatorValueDetails;
|
||||||
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
|
import org.hibernate.metamodel.spi.ImplicitDiscriminatorStrategy;
|
||||||
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
|
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.type.AnyDiscriminatorValueStrategy;
|
|
||||||
import org.hibernate.type.descriptor.java.CharacterJavaType;
|
import org.hibernate.type.descriptor.java.CharacterJavaType;
|
||||||
import org.hibernate.type.descriptor.java.JavaType;
|
import org.hibernate.type.descriptor.java.JavaType;
|
||||||
import org.hibernate.type.descriptor.java.StringJavaType;
|
import org.hibernate.type.descriptor.java.StringJavaType;
|
||||||
|
@ -24,45 +26,59 @@ import static org.hibernate.persister.entity.DiscriminatorHelper.NOT_NULL_DISCRI
|
||||||
import static org.hibernate.persister.entity.DiscriminatorHelper.NULL_DISCRIMINATOR;
|
import static org.hibernate.persister.entity.DiscriminatorHelper.NULL_DISCRIMINATOR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DiscriminatorConverter for use with {@linkplain org.hibernate.type.AnyDiscriminatorValueStrategy#MIXED}
|
|
||||||
*
|
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class MixedDiscriminatorConverter<O,R> extends DiscriminatorConverter<O,R> {
|
public class UnifiedAnyDiscriminatorConverter<O,R> extends DiscriminatorConverter<O,R> {
|
||||||
private final NavigableRole discriminatorRole;
|
private final NavigableRole discriminatorRole;
|
||||||
private final Map<Object, DiscriminatorValueDetails> detailsByValue;
|
private final Map<Object, DiscriminatorValueDetails> detailsByValue;
|
||||||
private final Map<String,DiscriminatorValueDetails> detailsByEntityName;
|
private final Map<String,DiscriminatorValueDetails> detailsByEntityName;
|
||||||
|
private final ImplicitDiscriminatorStrategy implicitValueStrategy;
|
||||||
private final MappingMetamodelImplementor mappingMetamodel;
|
private final MappingMetamodelImplementor mappingMetamodel;
|
||||||
|
|
||||||
public MixedDiscriminatorConverter(
|
public UnifiedAnyDiscriminatorConverter(
|
||||||
NavigableRole discriminatorRole,
|
NavigableRole discriminatorRole,
|
||||||
JavaType<O> domainJavaType,
|
JavaType<O> domainJavaType,
|
||||||
JavaType<R> relationalJavaType,
|
JavaType<R> relationalJavaType,
|
||||||
Map<Object,String> explicitValueMappings,
|
Map<Object,String> explicitValueMappings,
|
||||||
|
ImplicitDiscriminatorStrategy implicitValueStrategy,
|
||||||
MappingMetamodelImplementor mappingMetamodel) {
|
MappingMetamodelImplementor mappingMetamodel) {
|
||||||
super( discriminatorRole.getFullPath(), domainJavaType, relationalJavaType );
|
super( discriminatorRole.getFullPath(), domainJavaType, relationalJavaType );
|
||||||
this.discriminatorRole = discriminatorRole;
|
this.discriminatorRole = discriminatorRole;
|
||||||
this.mappingMetamodel = mappingMetamodel;
|
this.mappingMetamodel = mappingMetamodel;
|
||||||
|
|
||||||
|
this.implicitValueStrategy = resolveImplicitValueStrategy( implicitValueStrategy, explicitValueMappings );
|
||||||
|
|
||||||
this.detailsByValue = CollectionHelper.concurrentMap( explicitValueMappings.size() );
|
this.detailsByValue = CollectionHelper.concurrentMap( explicitValueMappings.size() );
|
||||||
this.detailsByEntityName = CollectionHelper.concurrentMap( explicitValueMappings.size() );
|
this.detailsByEntityName = CollectionHelper.concurrentMap( explicitValueMappings.size() );
|
||||||
explicitValueMappings.forEach( (value,entityName) -> {
|
explicitValueMappings.forEach( (value,entityName) -> {
|
||||||
String importedEntityName = mappingMetamodel.getImportedName( entityName );
|
final String importedEntityName = mappingMetamodel.getImportedName( entityName );
|
||||||
final EntityPersister entityDescriptor = mappingMetamodel.getEntityDescriptor( importedEntityName );
|
final EntityPersister entityMapping = mappingMetamodel.getEntityDescriptor( importedEntityName );
|
||||||
register( value, entityDescriptor );
|
register( value, entityMapping );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
private DiscriminatorValueDetails register(Object value, EntityPersister entityDescriptor) {
|
private ImplicitDiscriminatorStrategy resolveImplicitValueStrategy(ImplicitDiscriminatorStrategy implicitValueStrategy, Map<Object, String> explicitValueMappings) {
|
||||||
final DiscriminatorValueDetails details = new DiscriminatorValueDetailsImpl( value, entityDescriptor );
|
if ( explicitValueMappings.isEmpty() ) {
|
||||||
detailsByValue.put( value, details );
|
if ( implicitValueStrategy == null ) {
|
||||||
detailsByEntityName.put( entityDescriptor.getEntityName(), details );
|
return FullNameImplicitDiscriminatorStrategy.FULL_NAME_STRATEGY;
|
||||||
return details;
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( explicitValueMappings.containsKey( NOT_NULL_DISCRIMINATOR ) ) {
|
||||||
|
if ( implicitValueStrategy != null ) {
|
||||||
|
// we will ultimately not know how to handle "implicit" values which are non-null
|
||||||
|
throw new HibernateException( "Illegal use of ImplicitDiscriminatorStrategy with explicit non-null discriminator mapping: " + discriminatorRole.getFullPath() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return implicitValueStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private DiscriminatorValueDetails register(Object value, EntityMappingType entityMapping) {
|
||||||
public AnyDiscriminatorValueStrategy getValueStrategy() {
|
final DiscriminatorValueDetails details = new DiscriminatorValueDetailsImpl( value, entityMapping );
|
||||||
return AnyDiscriminatorValueStrategy.MIXED;
|
detailsByValue.put( value, details );
|
||||||
|
detailsByEntityName.put( entityMapping.getEntityName(), details );
|
||||||
|
return details;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Object, DiscriminatorValueDetails> getDetailsByValue() {
|
public Map<Object, DiscriminatorValueDetails> getDetailsByValue() {
|
||||||
|
@ -74,32 +90,26 @@ public class MixedDiscriminatorConverter<O,R> extends DiscriminatorConverter<O,R
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relationalForm) {
|
public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relationalValue) {
|
||||||
if ( relationalForm == null ) {
|
if ( relationalValue == null ) {
|
||||||
return detailsByValue.get( NULL_DISCRIMINATOR );
|
return detailsByValue.get( NULL_DISCRIMINATOR );
|
||||||
}
|
}
|
||||||
|
|
||||||
final DiscriminatorValueDetails existing = detailsByValue.get( relationalForm );
|
final DiscriminatorValueDetails existing = detailsByValue.get( relationalValue );
|
||||||
if ( existing != null ) {
|
if ( existing != null ) {
|
||||||
// an explicit or previously-resolved mapping
|
|
||||||
return existing;
|
return existing;
|
||||||
}
|
}
|
||||||
|
|
||||||
final DiscriminatorValueDetails notNullMatch = detailsByValue.get( NOT_NULL_DISCRIMINATOR );
|
if ( relationalValue.getClass().isEnum() ) {
|
||||||
if ( notNullMatch != null ) {
|
|
||||||
return notNullMatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( relationalForm.getClass().isEnum() ) {
|
|
||||||
final Object enumValue;
|
final Object enumValue;
|
||||||
if ( getRelationalJavaType() instanceof StringJavaType ) {
|
if ( getRelationalJavaType() instanceof StringJavaType ) {
|
||||||
enumValue = ( (Enum<?>) relationalForm ).name();
|
enumValue = ( (Enum<?>) relationalValue ).name();
|
||||||
}
|
}
|
||||||
else if ( getRelationalJavaType() instanceof CharacterJavaType ) {
|
else if ( getRelationalJavaType() instanceof CharacterJavaType ) {
|
||||||
enumValue = ( (Enum<?>) relationalForm ).name().charAt( 0 );
|
enumValue = ( (Enum<?>) relationalValue ).name().charAt( 0 );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
enumValue = ( (Enum<?>) relationalForm ).ordinal();
|
enumValue = ( (Enum<?>) relationalValue ).ordinal();
|
||||||
}
|
}
|
||||||
final DiscriminatorValueDetails enumMatch = detailsByValue.get( enumValue );
|
final DiscriminatorValueDetails enumMatch = detailsByValue.get( enumValue );
|
||||||
if ( enumMatch != null ) {
|
if ( enumMatch != null ) {
|
||||||
|
@ -107,15 +117,19 @@ public class MixedDiscriminatorConverter<O,R> extends DiscriminatorConverter<O,R
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( relationalForm instanceof String assumedEntityName ) {
|
if ( implicitValueStrategy != null ) {
|
||||||
// Assume the relational form is the entity name
|
final EntityMappingType entityMapping = implicitValueStrategy.toEntityMapping( relationalValue, discriminatorRole, mappingMetamodel );
|
||||||
final EntityPersister persister = mappingMetamodel.findEntityDescriptor( assumedEntityName );
|
if ( entityMapping != null ) {
|
||||||
if ( persister != null ) {
|
return register( relationalValue, entityMapping );
|
||||||
return register( assumedEntityName, persister );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new HibernateException( "Cannot interpret discriminator value (" + discriminatorRole + ") : " + relationalForm );
|
final DiscriminatorValueDetails nonNullMatch = detailsByValue.get( NOT_NULL_DISCRIMINATOR );
|
||||||
|
if ( nonNullMatch != null ) {
|
||||||
|
return nonNullMatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new HibernateException( "Unknown discriminator value (" + discriminatorRole.getFullPath() + ") : " + relationalValue );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -125,19 +139,29 @@ public class MixedDiscriminatorConverter<O,R> extends DiscriminatorConverter<O,R
|
||||||
return existing;
|
return existing;
|
||||||
}
|
}
|
||||||
|
|
||||||
final EntityPersister entityDescriptor = mappingMetamodel.getEntityDescriptor( entityName );
|
if ( implicitValueStrategy != null ) {
|
||||||
return register( entityName, entityDescriptor );
|
final EntityMappingType entityMapping = mappingMetamodel.getEntityDescriptor( entityName );
|
||||||
|
assert entityMapping != null;
|
||||||
|
final Object discriminatorValue = implicitValueStrategy.toDiscriminatorValue(
|
||||||
|
entityMapping,
|
||||||
|
discriminatorRole,
|
||||||
|
mappingMetamodel
|
||||||
|
);
|
||||||
|
return register( discriminatorValue, entityMapping );
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new HibernateException( "Cannot determine discriminator value from entity-name (" + discriminatorRole.getFullPath() + ") : " + entityName );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void forEachValueDetail(Consumer<DiscriminatorValueDetails> consumer) {
|
public void forEachValueDetail(Consumer<DiscriminatorValueDetails> consumer) {
|
||||||
detailsByEntityName.forEach( (value, detail) -> consumer.accept( detail ) );
|
detailsByEntityName.values().forEach( consumer );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <X> X fromValueDetails(Function<DiscriminatorValueDetails, X> handler) {
|
public <X> X fromValueDetails(Function<DiscriminatorValueDetails, X> handler) {
|
||||||
for ( DiscriminatorValueDetails detail : detailsByEntityName.values() ) {
|
for ( DiscriminatorValueDetails valueDetails : detailsByEntityName.values() ) {
|
||||||
final X result = handler.apply( detail );
|
final X result = handler.apply( valueDetails );
|
||||||
if ( result != null ) {
|
if ( result != null ) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
|
@ -48,7 +48,7 @@ public class AnyMappingDomainTypeImpl<T> implements AnyMappingDomainType<T> {
|
||||||
navigableRole,
|
navigableRole,
|
||||||
discriminatorBaseType,
|
discriminatorBaseType,
|
||||||
bootAnyMapping.getMetaValues(),
|
bootAnyMapping.getMetaValues(),
|
||||||
discriminatorType.getValueStrategy(),
|
discriminatorType.getImplicitValueStrategy(),
|
||||||
mappingMetamodel
|
mappingMetamodel
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.metamodel.spi;
|
||||||
|
|
||||||
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used in cases where we have no explicit {@linkplain org.hibernate.annotations.AnyDiscriminatorValue}
|
||||||
|
* mapping which matches.
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface ImplicitDiscriminatorStrategy {
|
||||||
|
/**
|
||||||
|
* Determine the discriminator value to use for the given {@code entityMapping}.
|
||||||
|
*/
|
||||||
|
Object toDiscriminatorValue(EntityMappingType entityMapping, NavigableRole discriminatorRole, MappingMetamodelImplementor mappingModel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the entity-mapping which matches the given {@code discriminatorValue}.
|
||||||
|
*/
|
||||||
|
EntityMappingType toEntityMapping(Object discriminatorValue, NavigableRole discriminatorRole, MappingMetamodelImplementor mappingModel);
|
||||||
|
}
|
|
@ -4,30 +4,7 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.persister.entity;
|
package org.hibernate.persister.entity;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.BitSet;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.SortedMap;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
import org.hibernate.AssertionFailure;
|
import org.hibernate.AssertionFailure;
|
||||||
import org.hibernate.FetchMode;
|
import org.hibernate.FetchMode;
|
||||||
import org.hibernate.Filter;
|
import org.hibernate.Filter;
|
||||||
|
@ -101,8 +78,8 @@ import org.hibernate.generator.Generator;
|
||||||
import org.hibernate.generator.OnExecutionGenerator;
|
import org.hibernate.generator.OnExecutionGenerator;
|
||||||
import org.hibernate.generator.internal.VersionGeneration;
|
import org.hibernate.generator.internal.VersionGeneration;
|
||||||
import org.hibernate.generator.values.GeneratedValues;
|
import org.hibernate.generator.values.GeneratedValues;
|
||||||
import org.hibernate.generator.values.internal.GeneratedValuesHelper;
|
|
||||||
import org.hibernate.generator.values.GeneratedValuesMutationDelegate;
|
import org.hibernate.generator.values.GeneratedValuesMutationDelegate;
|
||||||
|
import org.hibernate.generator.values.internal.GeneratedValuesHelper;
|
||||||
import org.hibernate.graph.spi.RootGraphImplementor;
|
import org.hibernate.graph.spi.RootGraphImplementor;
|
||||||
import org.hibernate.id.BulkInsertionCapableIdentifierGenerator;
|
import org.hibernate.id.BulkInsertionCapableIdentifierGenerator;
|
||||||
import org.hibernate.id.IdentifierGenerator;
|
import org.hibernate.id.IdentifierGenerator;
|
||||||
|
@ -120,6 +97,7 @@ import org.hibernate.internal.util.collections.ArrayHelper;
|
||||||
import org.hibernate.internal.util.collections.LockModeEnumMap;
|
import org.hibernate.internal.util.collections.LockModeEnumMap;
|
||||||
import org.hibernate.jdbc.Expectation;
|
import org.hibernate.jdbc.Expectation;
|
||||||
import org.hibernate.loader.ast.internal.CacheEntityLoaderHelper;
|
import org.hibernate.loader.ast.internal.CacheEntityLoaderHelper;
|
||||||
|
import org.hibernate.loader.ast.internal.EntityConcreteTypeLoader;
|
||||||
import org.hibernate.loader.ast.internal.LoaderSelectBuilder;
|
import org.hibernate.loader.ast.internal.LoaderSelectBuilder;
|
||||||
import org.hibernate.loader.ast.internal.LoaderSqlAstCreationState;
|
import org.hibernate.loader.ast.internal.LoaderSqlAstCreationState;
|
||||||
import org.hibernate.loader.ast.internal.MultiIdEntityLoaderArrayParam;
|
import org.hibernate.loader.ast.internal.MultiIdEntityLoaderArrayParam;
|
||||||
|
@ -180,11 +158,9 @@ import org.hibernate.metamodel.mapping.internal.CompoundNaturalIdMapping;
|
||||||
import org.hibernate.metamodel.mapping.internal.DiscriminatedAssociationAttributeMapping;
|
import org.hibernate.metamodel.mapping.internal.DiscriminatedAssociationAttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.internal.DiscriminatorTypeImpl;
|
import org.hibernate.metamodel.mapping.internal.DiscriminatorTypeImpl;
|
||||||
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
|
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
|
||||||
import org.hibernate.loader.ast.internal.EntityConcreteTypeLoader;
|
|
||||||
import org.hibernate.metamodel.mapping.internal.EntityRowIdMappingImpl;
|
import org.hibernate.metamodel.mapping.internal.EntityRowIdMappingImpl;
|
||||||
import org.hibernate.metamodel.mapping.internal.EntityVersionMappingImpl;
|
import org.hibernate.metamodel.mapping.internal.EntityVersionMappingImpl;
|
||||||
import org.hibernate.metamodel.mapping.internal.ExplicitColumnDiscriminatorMappingImpl;
|
import org.hibernate.metamodel.mapping.internal.ExplicitColumnDiscriminatorMappingImpl;
|
||||||
import org.hibernate.metamodel.mapping.internal.ExplicitDiscriminatorConverter;
|
|
||||||
import org.hibernate.metamodel.mapping.internal.GeneratedValuesProcessor;
|
import org.hibernate.metamodel.mapping.internal.GeneratedValuesProcessor;
|
||||||
import org.hibernate.metamodel.mapping.internal.ImmutableAttributeMappingList;
|
import org.hibernate.metamodel.mapping.internal.ImmutableAttributeMappingList;
|
||||||
import org.hibernate.metamodel.mapping.internal.InFlightEntityMappingType;
|
import org.hibernate.metamodel.mapping.internal.InFlightEntityMappingType;
|
||||||
|
@ -192,6 +168,7 @@ import org.hibernate.metamodel.mapping.internal.MappingModelCreationHelper;
|
||||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||||
import org.hibernate.metamodel.mapping.internal.SimpleAttributeMetadata;
|
import org.hibernate.metamodel.mapping.internal.SimpleAttributeMetadata;
|
||||||
import org.hibernate.metamodel.mapping.internal.SimpleNaturalIdMapping;
|
import org.hibernate.metamodel.mapping.internal.SimpleNaturalIdMapping;
|
||||||
|
import org.hibernate.metamodel.mapping.internal.UnifiedAnyDiscriminatorConverter;
|
||||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
import org.hibernate.metamodel.spi.EntityInstantiator;
|
import org.hibernate.metamodel.spi.EntityInstantiator;
|
||||||
import org.hibernate.metamodel.spi.EntityRepresentationStrategy;
|
import org.hibernate.metamodel.spi.EntityRepresentationStrategy;
|
||||||
|
@ -284,7 +261,29 @@ import org.hibernate.type.descriptor.java.MutabilityPlan;
|
||||||
import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry;
|
import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry;
|
||||||
import org.hibernate.type.spi.TypeConfiguration;
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import java.io.Serializable;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.BitSet;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.SortedMap;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.Collections.emptyMap;
|
import static java.util.Collections.emptyMap;
|
||||||
|
@ -2278,11 +2277,12 @@ public abstract class AbstractEntityPersister
|
||||||
}
|
}
|
||||||
|
|
||||||
//noinspection rawtypes
|
//noinspection rawtypes
|
||||||
final DiscriminatorConverter converter = new ExplicitDiscriminatorConverter(
|
final DiscriminatorConverter converter = new UnifiedAnyDiscriminatorConverter<>(
|
||||||
getNavigableRole().append( EntityDiscriminatorMapping.DISCRIMINATOR_ROLE_NAME ),
|
getNavigableRole().append( EntityDiscriminatorMapping.DISCRIMINATOR_ROLE_NAME ),
|
||||||
domainJavaType,
|
domainJavaType,
|
||||||
underlingJdbcMapping.getRelationalJavaType(),
|
underlingJdbcMapping.getRelationalJavaType(),
|
||||||
getSubclassByDiscriminatorValue(),
|
getSubclassByDiscriminatorValue(),
|
||||||
|
null,
|
||||||
factory.getMappingMetamodel()
|
factory.getMappingMetamodel()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
|
||||||
* Copyright Red Hat Inc. and Hibernate Authors
|
|
||||||
*/
|
|
||||||
package org.hibernate.type;
|
|
||||||
|
|
||||||
import org.hibernate.Incubating;
|
|
||||||
import org.hibernate.annotations.AnyDiscriminatorValue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Describes how to deal with discriminator values in regard to
|
|
||||||
* a {@linkplain org.hibernate.metamodel.mapping.DiscriminatedAssociationModelPart ANY mapping}
|
|
||||||
*
|
|
||||||
* @see AnyDiscriminatorValue
|
|
||||||
*
|
|
||||||
* @since 7.0
|
|
||||||
* @author Steve Ebersole
|
|
||||||
*/
|
|
||||||
@Incubating
|
|
||||||
public enum AnyDiscriminatorValueStrategy {
|
|
||||||
/**
|
|
||||||
* Pick between {@link #IMPLICIT} and {@link #EXPLICIT} based on
|
|
||||||
* presence or not of {@link AnyDiscriminatorValue}. The default
|
|
||||||
* (and legacy) behavior.
|
|
||||||
*/
|
|
||||||
AUTO,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Expect explicit, complete mapping of discriminator values using
|
|
||||||
* one-or-more {@link AnyDiscriminatorValue}.
|
|
||||||
*
|
|
||||||
* @implNote With this option, it is considered an error if, at runtime,
|
|
||||||
* we encounter an entity type not explicitly mapped with a
|
|
||||||
* {@link AnyDiscriminatorValue}.
|
|
||||||
*/
|
|
||||||
EXPLICIT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Expect no {@link AnyDiscriminatorValue}. The entity name of the associated
|
|
||||||
* entity is used as the discriminator value.
|
|
||||||
*
|
|
||||||
* @implNote With this option, it is considered illegal to specify
|
|
||||||
* any {@link AnyDiscriminatorValue} mappings.
|
|
||||||
*/
|
|
||||||
IMPLICIT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows a combination of {@linkplain #EXPLICIT explicit} and {@linkplain #IMPLICIT implicit}
|
|
||||||
* discriminator value mappings. If an entity is mapped using an explicit
|
|
||||||
* {@link AnyDiscriminatorValue} mapping, the associated discriminator value is used.
|
|
||||||
* Otherwise, the entity name is used.
|
|
||||||
*
|
|
||||||
* @implNote This option is roughly the same as {@link #EXPLICIT} except
|
|
||||||
* that an implicit mapping using the entity name is used when a matching
|
|
||||||
* explicit {@link AnyDiscriminatorValue} mapping is not found.
|
|
||||||
*/
|
|
||||||
MIXED
|
|
||||||
}
|
|
|
@ -4,14 +4,6 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.type;
|
package org.hibernate.type;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import org.hibernate.EntityNameResolver;
|
import org.hibernate.EntityNameResolver;
|
||||||
import org.hibernate.FetchMode;
|
import org.hibernate.FetchMode;
|
||||||
import org.hibernate.Hibernate;
|
import org.hibernate.Hibernate;
|
||||||
|
@ -30,8 +22,17 @@ import org.hibernate.persister.entity.Joinable;
|
||||||
import org.hibernate.proxy.LazyInitializer;
|
import org.hibernate.proxy.LazyInitializer;
|
||||||
import org.hibernate.type.spi.TypeConfiguration;
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import static org.hibernate.engine.internal.ForeignKeys.getEntityIdentifierIfNotUnsaved;
|
import static org.hibernate.engine.internal.ForeignKeys.getEntityIdentifierIfNotUnsaved;
|
||||||
import static org.hibernate.internal.util.collections.ArrayHelper.join;
|
import static org.hibernate.internal.util.collections.ArrayHelper.join;
|
||||||
|
import static org.hibernate.metamodel.internal.FullNameImplicitDiscriminatorStrategy.FULL_NAME_STRATEGY;
|
||||||
import static org.hibernate.pretty.MessageHelper.infoString;
|
import static org.hibernate.pretty.MessageHelper.infoString;
|
||||||
import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;
|
import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;
|
||||||
|
|
||||||
|
@ -71,7 +72,7 @@ public class AnyType extends AbstractType implements CompositeType, AssociationT
|
||||||
return metaType;
|
return metaType;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MetaType( discriminatorType, AnyDiscriminatorValueStrategy.AUTO, null );
|
return new MetaType( discriminatorType, FULL_NAME_STRATEGY, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type getIdentifierType() {
|
public Type getIdentifierType() {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import org.hibernate.engine.spi.Mapping;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||||
|
import org.hibernate.metamodel.spi.ImplicitDiscriminatorStrategy;
|
||||||
|
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
@ -25,47 +26,36 @@ public class MetaType extends AbstractType {
|
||||||
public static final String[] REGISTRATION_KEYS = ArrayHelper.EMPTY_STRING_ARRAY;
|
public static final String[] REGISTRATION_KEYS = ArrayHelper.EMPTY_STRING_ARRAY;
|
||||||
|
|
||||||
private final Type valueType;
|
private final Type valueType;
|
||||||
private final AnyDiscriminatorValueStrategy valueStrategy;
|
private final ImplicitDiscriminatorStrategy implicitValueStrategy;
|
||||||
private final Map<Object,String> discriminatorValuesToEntityNameMap;
|
private final Map<Object,String> discriminatorValuesToEntityNameMap;
|
||||||
private final Map<String,Object> entityNameToDiscriminatorValueMap;
|
private final Map<String,Object> entityNameToDiscriminatorValueMap;
|
||||||
|
|
||||||
public MetaType(
|
public MetaType(
|
||||||
Type valueType,
|
Type valueType,
|
||||||
AnyDiscriminatorValueStrategy valueStrategy,
|
ImplicitDiscriminatorStrategy implicitValueStrategy,
|
||||||
Map<Object,String> explicitValueMappings) {
|
Map<Object,String> explicitValueMappings) {
|
||||||
this.valueType = valueType;
|
this.valueType = valueType;
|
||||||
|
this.implicitValueStrategy = implicitValueStrategy;
|
||||||
|
|
||||||
if ( explicitValueMappings == null || explicitValueMappings.isEmpty() ) {
|
if ( explicitValueMappings == null || explicitValueMappings.isEmpty() ) {
|
||||||
if ( valueStrategy == AnyDiscriminatorValueStrategy.AUTO ) {
|
|
||||||
valueStrategy = AnyDiscriminatorValueStrategy.IMPLICIT;
|
|
||||||
}
|
|
||||||
this.discriminatorValuesToEntityNameMap = new HashMap<>();
|
this.discriminatorValuesToEntityNameMap = new HashMap<>();
|
||||||
this.entityNameToDiscriminatorValueMap = new HashMap<>();
|
this.entityNameToDiscriminatorValueMap = new HashMap<>();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ( valueStrategy == AnyDiscriminatorValueStrategy.AUTO ) {
|
|
||||||
valueStrategy = AnyDiscriminatorValueStrategy.EXPLICIT;
|
|
||||||
}
|
|
||||||
this.discriminatorValuesToEntityNameMap = explicitValueMappings;
|
this.discriminatorValuesToEntityNameMap = explicitValueMappings;
|
||||||
this.entityNameToDiscriminatorValueMap = new HashMap<>();
|
this.entityNameToDiscriminatorValueMap = new HashMap<>();
|
||||||
for ( Map.Entry<Object,String> entry : discriminatorValuesToEntityNameMap.entrySet() ) {
|
for ( Map.Entry<Object,String> entry : discriminatorValuesToEntityNameMap.entrySet() ) {
|
||||||
entityNameToDiscriminatorValueMap.put( entry.getValue(), entry.getKey() );
|
entityNameToDiscriminatorValueMap.put( entry.getValue(), entry.getKey() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.valueStrategy = valueStrategy;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MetaType(Map<Object,String> discriminatorValuesToEntityNameMap, Type baseType) {
|
|
||||||
this( baseType, AnyDiscriminatorValueStrategy.AUTO, discriminatorValuesToEntityNameMap );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type getBaseType() {
|
public Type getBaseType() {
|
||||||
return valueType;
|
return valueType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AnyDiscriminatorValueStrategy getValueStrategy() {
|
public ImplicitDiscriminatorStrategy getImplicitValueStrategy() {
|
||||||
return valueStrategy;
|
return implicitValueStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] getRegistrationKeys() {
|
public String[] getRegistrationKeys() {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
* Copyright Red Hat Inc. and Hibernate Authors
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
*/
|
*/
|
||||||
package org.hibernate.orm.test.any.mixed;
|
package org.hibernate.orm.test.any.discriminator;
|
||||||
|
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
|
@ -11,8 +11,12 @@ import jakarta.persistence.Id;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Entity(name = "CardPayment")
|
//tag::associations-any-example[]
|
||||||
|
@Entity
|
||||||
public class CardPayment implements Payment {
|
public class CardPayment implements Payment {
|
||||||
|
// ...
|
||||||
|
//end::associations-any-example[]
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
private Integer id;
|
private Integer id;
|
||||||
private Double amount;
|
private Double amount;
|
||||||
|
@ -47,4 +51,6 @@ public class CardPayment implements Payment {
|
||||||
public void setAuthorizationCode(String authorizationCode) {
|
public void setAuthorizationCode(String authorizationCode) {
|
||||||
this.authorizationCode = authorizationCode;
|
this.authorizationCode = authorizationCode;
|
||||||
}
|
}
|
||||||
|
//tag::associations-any-example[]
|
||||||
}
|
}
|
||||||
|
//end::associations-any-example[]
|
|
@ -2,7 +2,7 @@
|
||||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
* Copyright Red Hat Inc. and Hibernate Authors
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
*/
|
*/
|
||||||
package org.hibernate.orm.test.any.mixed;
|
package org.hibernate.orm.test.any.discriminator;
|
||||||
|
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
|
@ -11,8 +11,11 @@ import jakarta.persistence.Id;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Entity(name = "CashPayment")
|
//tag::associations-any-example[]
|
||||||
|
@Entity
|
||||||
public class CashPayment implements Payment {
|
public class CashPayment implements Payment {
|
||||||
|
// ...
|
||||||
|
//end::associations-any-example[]
|
||||||
@Id
|
@Id
|
||||||
private Integer id;
|
private Integer id;
|
||||||
private Double amount;
|
private Double amount;
|
||||||
|
@ -37,4 +40,6 @@ public class CashPayment implements Payment {
|
||||||
public void setAmount(Double amount) {
|
public void setAmount(Double amount) {
|
||||||
this.amount = amount;
|
this.amount = amount;
|
||||||
}
|
}
|
||||||
|
//tag::associations-any-example[]
|
||||||
}
|
}
|
||||||
|
//end::associations-any-example[]
|
|
@ -2,7 +2,7 @@
|
||||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
* Copyright Red Hat Inc. and Hibernate Authors
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
*/
|
*/
|
||||||
package org.hibernate.orm.test.any.mixed;
|
package org.hibernate.orm.test.any.discriminator;
|
||||||
|
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
|
@ -11,8 +11,11 @@ import jakarta.persistence.Id;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
//tag::associations-any-example[]
|
||||||
@Entity
|
@Entity
|
||||||
public class CheckPayment implements Payment {
|
public class CheckPayment implements Payment {
|
||||||
|
// ...
|
||||||
|
//end::associations-any-example[]
|
||||||
@Id
|
@Id
|
||||||
public Integer id;
|
public Integer id;
|
||||||
public Double amount;
|
public Double amount;
|
||||||
|
@ -35,4 +38,6 @@ public class CheckPayment implements Payment {
|
||||||
public Double getAmount() {
|
public Double getAmount() {
|
||||||
return amount;
|
return amount;
|
||||||
}
|
}
|
||||||
|
//tag::associations-any-example[]
|
||||||
}
|
}
|
||||||
|
//end::associations-any-example[]
|
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.any.discriminator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
//tag::associations-any-example[]
|
||||||
|
public interface Payment {
|
||||||
|
// ...
|
||||||
|
//end::associations-any-example[]
|
||||||
|
Double getAmount();
|
||||||
|
//tag::associations-any-example[]
|
||||||
|
}
|
||||||
|
//end::associations-any-example[]
|
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.any.discriminator.explicit;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.CardPayment;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.CashPayment;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.CheckPayment;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.Payment;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.Statement;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.fail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("JUnitMalformedDeclaration")
|
||||||
|
@DomainModel(annotatedClasses = {Payment.class, CashPayment.class, CardPayment.class, CheckPayment.class, Order.class})
|
||||||
|
@SessionFactory
|
||||||
|
public class ExplicitValueTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void verifyExplicitMappingHandling(SessionFactoryScope sessions) {
|
||||||
|
sessions.inTransaction( (session) -> {
|
||||||
|
final Order order = session.find( Order.class, 1 );
|
||||||
|
final CashPayment cashPayment = session.find( CashPayment.class, 1 );
|
||||||
|
final CardPayment cardPayment = session.find( CardPayment.class, 1 );
|
||||||
|
final CheckPayment checkPayment = session.find( CheckPayment.class, 1 );
|
||||||
|
|
||||||
|
order.paymentExplicit = cardPayment;
|
||||||
|
session.flush();
|
||||||
|
verifyDiscriminatorValue( "explicit_type", "CARD", session );
|
||||||
|
|
||||||
|
order.paymentExplicit = checkPayment;
|
||||||
|
session.flush();
|
||||||
|
verifyDiscriminatorValue( "explicit_type", "CHECK", session );
|
||||||
|
|
||||||
|
// NOTE : cash is not explicitly mapped and implicit mappings are not enabled, so this should be an error
|
||||||
|
try {
|
||||||
|
order.paymentExplicit = cashPayment;
|
||||||
|
session.flush();
|
||||||
|
fail( "Expecting an error" );
|
||||||
|
}
|
||||||
|
catch (HibernateException expected) {
|
||||||
|
assertThat( expected ).hasMessageContaining( "Cannot determine discriminator value from entity-name" );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyDiscriminatorValue(String columnName, String expectedValue, SessionImplementor session) {
|
||||||
|
final String qry = String.format( "select %s from orders", columnName );
|
||||||
|
session.doWork( (connection) -> {
|
||||||
|
try (final Statement stmnt = connection.createStatement() ) {
|
||||||
|
try (ResultSet resultSet = stmnt.executeQuery( qry )) {
|
||||||
|
assertThat( resultSet.next() ).isTrue();
|
||||||
|
final String discriminatorValue = resultSet.getString( columnName );
|
||||||
|
assertThat( resultSet.next() ).isFalse();
|
||||||
|
assertThat( discriminatorValue ).isEqualTo( expectedValue );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void prepareTestData(SessionFactoryScope sessions) {
|
||||||
|
sessions.inTransaction( (session) -> {
|
||||||
|
final Order order = new Order( 1, "1" );
|
||||||
|
final CashPayment cashPayment = new CashPayment( 1, 50.00 );
|
||||||
|
final CardPayment cardPayment = new CardPayment( 1, 150.00, "123-456-789" );
|
||||||
|
final CheckPayment checkPayment = new CheckPayment( 1, 250.00, 1001, "123", "987" );
|
||||||
|
session.persist( order );
|
||||||
|
session.persist( cashPayment );
|
||||||
|
session.persist( cardPayment );
|
||||||
|
session.persist( checkPayment );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
void dropTestData(SessionFactoryScope sessions) {
|
||||||
|
sessions.inTransaction( (session) -> {
|
||||||
|
session.createMutationQuery( "delete Order" ).executeUpdate();
|
||||||
|
session.createMutationQuery( "delete CashPayment" ).executeUpdate();
|
||||||
|
session.createMutationQuery( "delete CardPayment" ).executeUpdate();
|
||||||
|
session.createMutationQuery( "delete CheckPayment" ).executeUpdate();
|
||||||
|
} );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,18 +2,20 @@
|
||||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
* Copyright Red Hat Inc. and Hibernate Authors
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
*/
|
*/
|
||||||
package org.hibernate.orm.test.any.mixed;
|
package org.hibernate.orm.test.any.discriminator.explicit;
|
||||||
|
|
||||||
|
import jakarta.persistence.Basic;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import jakarta.persistence.Basic;
|
|
||||||
import jakarta.persistence.JoinColumn;
|
import jakarta.persistence.JoinColumn;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import org.hibernate.annotations.Any;
|
import org.hibernate.annotations.Any;
|
||||||
import org.hibernate.annotations.AnyDiscriminator;
|
|
||||||
import org.hibernate.annotations.AnyDiscriminatorValue;
|
import org.hibernate.annotations.AnyDiscriminatorValue;
|
||||||
import org.hibernate.annotations.AnyKeyJavaClass;
|
import org.hibernate.annotations.AnyKeyJavaClass;
|
||||||
import org.hibernate.type.AnyDiscriminatorValueStrategy;
|
import org.hibernate.orm.test.any.discriminator.CardPayment;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.CheckPayment;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.Payment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
@ -26,25 +28,15 @@ public class Order {
|
||||||
@Basic
|
@Basic
|
||||||
public String name;
|
public String name;
|
||||||
|
|
||||||
|
//tag::associations-any-explicit-discriminator-example[]
|
||||||
@Any
|
@Any
|
||||||
@AnyKeyJavaClass( Integer.class )
|
@AnyKeyJavaClass( Integer.class )
|
||||||
@JoinColumn(name = "explicit_fk")
|
@JoinColumn(name = "explicit_fk")
|
||||||
|
@Column( name="explicit_type" )
|
||||||
@AnyDiscriminatorValue( discriminator = "CARD", entity = CardPayment.class )
|
@AnyDiscriminatorValue( discriminator = "CARD", entity = CardPayment.class )
|
||||||
@AnyDiscriminatorValue( discriminator = "CHECK", entity = CheckPayment.class )
|
@AnyDiscriminatorValue( discriminator = "CHECK", entity = CheckPayment.class )
|
||||||
public Payment explicitPayment;
|
public Payment paymentExplicit;
|
||||||
|
//end::associations-any-explicit-discriminator-example[]
|
||||||
@Any
|
|
||||||
@AnyKeyJavaClass( Integer.class )
|
|
||||||
@JoinColumn(name = "implicit_fk")
|
|
||||||
public Payment implicitPayment;
|
|
||||||
|
|
||||||
@Any
|
|
||||||
@AnyKeyJavaClass( Integer.class )
|
|
||||||
@JoinColumn(name = "mixed_fk")
|
|
||||||
@AnyDiscriminator(valueStrategy = AnyDiscriminatorValueStrategy.MIXED)
|
|
||||||
@AnyDiscriminatorValue( discriminator = "CARD", entity = CardPayment.class )
|
|
||||||
@AnyDiscriminatorValue( discriminator = "CHECK", entity = CheckPayment.class )
|
|
||||||
public Payment mixedPayment;
|
|
||||||
|
|
||||||
protected Order() {
|
protected Order() {
|
||||||
// for Hibernate use
|
// for Hibernate use
|
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.any.discriminator.implicit;
|
||||||
|
|
||||||
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.CardPayment;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.CashPayment;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.CheckPayment;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.Payment;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.Statement;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("JUnitMalformedDeclaration")
|
||||||
|
@DomainModel(annotatedClasses = {Payment.class, CashPayment.class, CardPayment.class, CheckPayment.class, Order.class})
|
||||||
|
@SessionFactory
|
||||||
|
public class ImplicitValueTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void verifyImplicitMappingHandling(SessionFactoryScope sessions) {
|
||||||
|
sessions.inTransaction( (session) -> {
|
||||||
|
final Order order = session.find( Order.class, 1 );
|
||||||
|
final CashPayment cashPayment = session.find( CashPayment.class, 1 );
|
||||||
|
final CardPayment cardPayment = session.find( CardPayment.class, 1 );
|
||||||
|
final CheckPayment checkPayment = session.find( CheckPayment.class, 1 );
|
||||||
|
|
||||||
|
order.paymentImplicit = cardPayment;
|
||||||
|
order.paymentImplicitFullName = cardPayment;
|
||||||
|
order.paymentImplicitShortName = cardPayment;
|
||||||
|
session.flush();
|
||||||
|
verifyDiscriminatorValue( "implicit_type", CardPayment.class.getName(), session );
|
||||||
|
verifyDiscriminatorValue( "implicit_full_type", CardPayment.class.getName(), session );
|
||||||
|
verifyDiscriminatorValue( "implicit_short_type", CardPayment.class.getSimpleName(), session );
|
||||||
|
|
||||||
|
order.paymentImplicit = checkPayment;
|
||||||
|
order.paymentImplicitFullName = checkPayment;
|
||||||
|
order.paymentImplicitShortName = checkPayment;
|
||||||
|
session.flush();
|
||||||
|
verifyDiscriminatorValue( "implicit_type", CheckPayment.class.getName(), session );
|
||||||
|
verifyDiscriminatorValue( "implicit_full_type", CheckPayment.class.getName(), session );
|
||||||
|
verifyDiscriminatorValue( "implicit_short_type", CheckPayment.class.getSimpleName(), session );
|
||||||
|
|
||||||
|
order.paymentImplicit = cashPayment;
|
||||||
|
order.paymentImplicitFullName = cashPayment;
|
||||||
|
order.paymentImplicitShortName = cashPayment;
|
||||||
|
session.flush();
|
||||||
|
verifyDiscriminatorValue( "implicit_type", CashPayment.class.getName(), session );
|
||||||
|
verifyDiscriminatorValue( "implicit_full_type", CashPayment.class.getName(), session );
|
||||||
|
verifyDiscriminatorValue( "implicit_short_type", CashPayment.class.getSimpleName(), session );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyDiscriminatorValue(String columnName, String expectedValue, SessionImplementor session) {
|
||||||
|
final String qry = String.format( "select %s from orders", columnName );
|
||||||
|
session.doWork( (connection) -> {
|
||||||
|
try (final Statement stmnt = connection.createStatement() ) {
|
||||||
|
try (ResultSet resultSet = stmnt.executeQuery( qry )) {
|
||||||
|
assertThat( resultSet.next() ).isTrue();
|
||||||
|
final String discriminatorValue = resultSet.getString( columnName );
|
||||||
|
assertThat( resultSet.next() ).isFalse();
|
||||||
|
assertThat( discriminatorValue ).isEqualTo( expectedValue );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void prepareTestData(SessionFactoryScope sessions) {
|
||||||
|
sessions.inTransaction( (session) -> {
|
||||||
|
final Order order = new Order( 1, "1" );
|
||||||
|
final CashPayment cashPayment = new CashPayment( 1, 50.00 );
|
||||||
|
final CardPayment cardPayment = new CardPayment( 1, 150.00, "123-456-789" );
|
||||||
|
final CheckPayment checkPayment = new CheckPayment( 1, 250.00, 1001, "123", "987" );
|
||||||
|
session.persist( order );
|
||||||
|
session.persist( cashPayment );
|
||||||
|
session.persist( cardPayment );
|
||||||
|
session.persist( checkPayment );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
void dropTestData(SessionFactoryScope sessions) {
|
||||||
|
sessions.inTransaction( (session) -> {
|
||||||
|
session.createMutationQuery( "delete Order" ).executeUpdate();
|
||||||
|
session.createMutationQuery( "delete CashPayment" ).executeUpdate();
|
||||||
|
session.createMutationQuery( "delete CardPayment" ).executeUpdate();
|
||||||
|
session.createMutationQuery( "delete CheckPayment" ).executeUpdate();
|
||||||
|
} );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.any.discriminator.implicit;
|
||||||
|
|
||||||
|
import jakarta.persistence.Basic;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import org.hibernate.annotations.Any;
|
||||||
|
import org.hibernate.annotations.AnyDiscriminatorImplicitValues;
|
||||||
|
import org.hibernate.annotations.AnyKeyJavaClass;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.Payment;
|
||||||
|
|
||||||
|
import static org.hibernate.annotations.AnyDiscriminatorImplicitValues.Strategy.FULL_NAME;
|
||||||
|
import static org.hibernate.annotations.AnyDiscriminatorImplicitValues.Strategy.SHORT_NAME;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "orders")
|
||||||
|
public class Order {
|
||||||
|
@Id
|
||||||
|
public Integer id;
|
||||||
|
@Basic
|
||||||
|
public String name;
|
||||||
|
|
||||||
|
//tag::associations-any-implicit-discriminator-example[]
|
||||||
|
@Any
|
||||||
|
@AnyKeyJavaClass( Integer.class )
|
||||||
|
@JoinColumn(name = "implicit_fk")
|
||||||
|
@Column(name = "implicit_type")
|
||||||
|
public Payment paymentImplicit;
|
||||||
|
//end::associations-any-implicit-discriminator-example[]
|
||||||
|
|
||||||
|
//tag::associations-any-implicit-discriminator-full-example[]
|
||||||
|
@Any
|
||||||
|
@AnyKeyJavaClass( Integer.class )
|
||||||
|
@JoinColumn(name = "implicit_full_fk")
|
||||||
|
@Column(name = "implicit_full_type")
|
||||||
|
@AnyDiscriminatorImplicitValues(FULL_NAME)
|
||||||
|
public Payment paymentImplicitFullName;
|
||||||
|
//end::associations-any-implicit-discriminator-full-example[]
|
||||||
|
|
||||||
|
//tag::associations-any-implicit-discriminator-short-example[]
|
||||||
|
@Any
|
||||||
|
@AnyKeyJavaClass( Integer.class )
|
||||||
|
@JoinColumn(name = "implicit_short_fk")
|
||||||
|
@Column(name = "implicit_short_type")
|
||||||
|
@AnyDiscriminatorImplicitValues(SHORT_NAME)
|
||||||
|
public Payment paymentImplicitShortName;
|
||||||
|
//end::associations-any-implicit-discriminator-short-example[]
|
||||||
|
|
||||||
|
protected Order() {
|
||||||
|
// for Hibernate use
|
||||||
|
}
|
||||||
|
|
||||||
|
public Order(Integer id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.any.discriminator.many;
|
||||||
|
|
||||||
|
import jakarta.persistence.Basic;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.DiscriminatorType;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.JoinTable;
|
||||||
|
import org.hibernate.annotations.AnyDiscriminator;
|
||||||
|
import org.hibernate.annotations.AnyDiscriminatorImplicitValues;
|
||||||
|
import org.hibernate.annotations.AnyDiscriminatorValue;
|
||||||
|
import org.hibernate.annotations.AnyKeyJavaClass;
|
||||||
|
import org.hibernate.annotations.ManyToAny;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.CardPayment;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.CheckPayment;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.Payment;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.hibernate.annotations.AnyDiscriminatorImplicitValues.Strategy.SHORT_NAME;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
public class Loan {
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
@Basic
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
//tag::associations-many-to-any-example[]
|
||||||
|
@ManyToAny
|
||||||
|
@AnyDiscriminator(DiscriminatorType.STRING)
|
||||||
|
@Column(name = "payment_type")
|
||||||
|
@AnyKeyJavaClass(Integer.class)
|
||||||
|
@AnyDiscriminatorValue( discriminator = "CARD", entity = CardPayment.class )
|
||||||
|
@AnyDiscriminatorValue( discriminator = "CHECK", entity = CheckPayment.class )
|
||||||
|
@AnyDiscriminatorImplicitValues(SHORT_NAME)
|
||||||
|
@JoinTable(name = "loan_payments",
|
||||||
|
joinColumns = @JoinColumn(name = "loan_fk"),
|
||||||
|
inverseJoinColumns = @JoinColumn(name = "payment_fk")
|
||||||
|
)
|
||||||
|
private Set<Payment> payments;
|
||||||
|
//end::associations-many-to-any-example[]
|
||||||
|
|
||||||
|
protected Loan() {
|
||||||
|
// for Hibernate use
|
||||||
|
}
|
||||||
|
|
||||||
|
public Loan(Integer id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Payment> getPayments() {
|
||||||
|
return payments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayments(Set<Payment> payments) {
|
||||||
|
this.payments = payments;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.any.discriminator.many;
|
||||||
|
|
||||||
|
import org.hibernate.orm.test.any.discriminator.CardPayment;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.CashPayment;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.CheckPayment;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.Payment;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("JUnitMalformedDeclaration")
|
||||||
|
@DomainModel(annotatedClasses = {Payment.class, CashPayment.class, CardPayment.class, CheckPayment.class, Loan.class})
|
||||||
|
@SessionFactory
|
||||||
|
public class ManyToAnyTests {
|
||||||
|
@Test
|
||||||
|
public void testManyToAnyUsage(SessionFactoryScope sessions) {
|
||||||
|
sessions.inTransaction( (session) -> {
|
||||||
|
final Loan loan = session.find( Loan.class, 1 );
|
||||||
|
final CashPayment cashPayment = session.find( CashPayment.class, 1 );
|
||||||
|
final CardPayment cardPayment = session.find( CardPayment.class, 1 );
|
||||||
|
final CheckPayment checkPayment = session.find( CheckPayment.class, 1 );
|
||||||
|
|
||||||
|
loan.getPayments().add( cardPayment );
|
||||||
|
session.flush();
|
||||||
|
|
||||||
|
loan.getPayments().add( checkPayment );
|
||||||
|
session.flush();
|
||||||
|
|
||||||
|
loan.getPayments().add( cashPayment );
|
||||||
|
session.flush();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void prepareTestData(SessionFactoryScope sessions) {
|
||||||
|
sessions.inTransaction( (session) -> {
|
||||||
|
final Loan loan = new Loan( 1, "1" );
|
||||||
|
final CashPayment cashPayment = new CashPayment( 1, 50.00 );
|
||||||
|
final CardPayment cardPayment = new CardPayment( 1, 150.00, "123-456-789" );
|
||||||
|
final CheckPayment checkPayment = new CheckPayment( 1, 250.00, 1001, "123", "987" );
|
||||||
|
session.persist( loan );
|
||||||
|
session.persist( cashPayment );
|
||||||
|
session.persist( cardPayment );
|
||||||
|
session.persist( checkPayment );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
void dropTestData(SessionFactoryScope sessions) {
|
||||||
|
sessions.inTransaction( (session) -> {
|
||||||
|
session.createMutationQuery( "delete Loan" ).executeUpdate();
|
||||||
|
session.createMutationQuery( "delete CashPayment" ).executeUpdate();
|
||||||
|
session.createMutationQuery( "delete CardPayment" ).executeUpdate();
|
||||||
|
session.createMutationQuery( "delete CheckPayment" ).executeUpdate();
|
||||||
|
} );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.any.discriminator.meta;
|
||||||
|
|
||||||
|
import jakarta.persistence.Basic;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import org.hibernate.annotations.Any;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.Payment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "orders")
|
||||||
|
public class Order {
|
||||||
|
@Id
|
||||||
|
public Integer id;
|
||||||
|
@Basic
|
||||||
|
public String name;
|
||||||
|
|
||||||
|
//tag::associations-any-discriminator-meta-example[]
|
||||||
|
@Any
|
||||||
|
@PaymentDiscriminationDef
|
||||||
|
@Column(name = "payment_type")
|
||||||
|
@JoinColumn(name = "payment_fk")
|
||||||
|
public Payment payment;
|
||||||
|
//end::associations-any-discriminator-meta-example[]
|
||||||
|
|
||||||
|
protected Order() {
|
||||||
|
// for Hibernate use
|
||||||
|
}
|
||||||
|
|
||||||
|
public Order(Integer id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.any.discriminator.meta;
|
||||||
|
|
||||||
|
import jakarta.persistence.DiscriminatorType;
|
||||||
|
import org.hibernate.annotations.AnyDiscriminator;
|
||||||
|
import org.hibernate.annotations.AnyDiscriminatorImplicitValues;
|
||||||
|
import org.hibernate.annotations.AnyDiscriminatorValue;
|
||||||
|
import org.hibernate.annotations.AnyKeyJavaClass;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.CardPayment;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.CheckPayment;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import static org.hibernate.annotations.AnyDiscriminatorImplicitValues.Strategy.SHORT_NAME;
|
||||||
|
|
||||||
|
|
||||||
|
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
|
||||||
|
@AnyDiscriminator(DiscriminatorType.STRING)
|
||||||
|
@AnyKeyJavaClass(Long.class)
|
||||||
|
|
||||||
|
@AnyDiscriminatorValue(discriminator = "CARD", entity = CardPayment.class)
|
||||||
|
@AnyDiscriminatorValue(discriminator = "CHECK", entity = CheckPayment.class)
|
||||||
|
@AnyDiscriminatorImplicitValues(SHORT_NAME)
|
||||||
|
public @interface PaymentDiscriminationDef {
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.any.discriminator.mixed;
|
||||||
|
|
||||||
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.CardPayment;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.CashPayment;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.CheckPayment;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.Payment;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.Statement;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("JUnitMalformedDeclaration")
|
||||||
|
@DomainModel(annotatedClasses = {Payment.class, CashPayment.class, CardPayment.class, CheckPayment.class, Order.class})
|
||||||
|
@SessionFactory
|
||||||
|
public class MixedValueTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void verifyImplicitMappingHandling(SessionFactoryScope sessions) {
|
||||||
|
sessions.inTransaction( (session) -> {
|
||||||
|
final Order order = session.find( Order.class, 1 );
|
||||||
|
final CashPayment cashPayment = session.find( CashPayment.class, 1 );
|
||||||
|
final CardPayment cardPayment = session.find( CardPayment.class, 1 );
|
||||||
|
final CheckPayment checkPayment = session.find( CheckPayment.class, 1 );
|
||||||
|
|
||||||
|
order.paymentMixedFullName = cardPayment;
|
||||||
|
order.paymentMixedShortName = cardPayment;
|
||||||
|
session.flush();
|
||||||
|
verifyDiscriminatorValue( "full_mixed_type", "CARD", session );
|
||||||
|
verifyDiscriminatorValue( "short_mixed_type", "CARD", session );
|
||||||
|
|
||||||
|
order.paymentMixedFullName = checkPayment;
|
||||||
|
order.paymentMixedShortName = checkPayment;
|
||||||
|
session.flush();
|
||||||
|
verifyDiscriminatorValue( "full_mixed_type", "CHECK", session );
|
||||||
|
verifyDiscriminatorValue( "short_mixed_type", "CHECK", session );
|
||||||
|
|
||||||
|
order.paymentMixedFullName = cashPayment;
|
||||||
|
order.paymentMixedShortName = cashPayment;
|
||||||
|
session.flush();
|
||||||
|
verifyDiscriminatorValue( "full_mixed_type", CashPayment.class.getName(), session );
|
||||||
|
verifyDiscriminatorValue( "short_mixed_type", CashPayment.class.getSimpleName(), session );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyDiscriminatorValue(String columnName, String expectedValue, SessionImplementor session) {
|
||||||
|
final String qry = String.format( "select %s from orders", columnName );
|
||||||
|
session.doWork( (connection) -> {
|
||||||
|
try (final Statement stmnt = connection.createStatement() ) {
|
||||||
|
try (ResultSet resultSet = stmnt.executeQuery( qry )) {
|
||||||
|
assertThat( resultSet.next() ).isTrue();
|
||||||
|
final String discriminatorValue = resultSet.getString( columnName );
|
||||||
|
assertThat( resultSet.next() ).isFalse();
|
||||||
|
assertThat( discriminatorValue ).isEqualTo( expectedValue );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void prepareTestData(SessionFactoryScope sessions) {
|
||||||
|
sessions.inTransaction( (session) -> {
|
||||||
|
final Order order = new Order( 1, "1" );
|
||||||
|
final CashPayment cashPayment = new CashPayment( 1, 50.00 );
|
||||||
|
final CardPayment cardPayment = new CardPayment( 1, 150.00, "123-456-789" );
|
||||||
|
final CheckPayment checkPayment = new CheckPayment( 1, 250.00, 1001, "123", "987" );
|
||||||
|
session.persist( order );
|
||||||
|
session.persist( cashPayment );
|
||||||
|
session.persist( cardPayment );
|
||||||
|
session.persist( checkPayment );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
void dropTestData(SessionFactoryScope sessions) {
|
||||||
|
sessions.inTransaction( (session) -> {
|
||||||
|
session.createMutationQuery( "delete Order" ).executeUpdate();
|
||||||
|
session.createMutationQuery( "delete CashPayment" ).executeUpdate();
|
||||||
|
session.createMutationQuery( "delete CardPayment" ).executeUpdate();
|
||||||
|
session.createMutationQuery( "delete CheckPayment" ).executeUpdate();
|
||||||
|
} );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.any.discriminator.mixed;
|
||||||
|
|
||||||
|
import jakarta.persistence.Basic;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import org.hibernate.annotations.Any;
|
||||||
|
import org.hibernate.annotations.AnyDiscriminatorImplicitValues;
|
||||||
|
import org.hibernate.annotations.AnyDiscriminatorValue;
|
||||||
|
import org.hibernate.annotations.AnyKeyJavaClass;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.CardPayment;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.CheckPayment;
|
||||||
|
import org.hibernate.orm.test.any.discriminator.Payment;
|
||||||
|
|
||||||
|
import static org.hibernate.annotations.AnyDiscriminatorImplicitValues.Strategy.FULL_NAME;
|
||||||
|
import static org.hibernate.annotations.AnyDiscriminatorImplicitValues.Strategy.SHORT_NAME;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "orders")
|
||||||
|
public class Order {
|
||||||
|
@Id
|
||||||
|
public Integer id;
|
||||||
|
@Basic
|
||||||
|
public String name;
|
||||||
|
|
||||||
|
//tag::associations-any-mixed-discriminator-full-example[]
|
||||||
|
@Any
|
||||||
|
@AnyKeyJavaClass( Integer.class )
|
||||||
|
@JoinColumn(name = "full_mixed_fk")
|
||||||
|
@Column(name = "full_mixed_type")
|
||||||
|
@AnyDiscriminatorImplicitValues(FULL_NAME)
|
||||||
|
@AnyDiscriminatorValue( discriminator = "CARD", entity = CardPayment.class )
|
||||||
|
@AnyDiscriminatorValue( discriminator = "CHECK", entity = CheckPayment.class )
|
||||||
|
public Payment paymentMixedFullName;
|
||||||
|
//end::associations-any-mixed-discriminator-full-example[]
|
||||||
|
|
||||||
|
//tag::associations-any-mixed-discriminator-short-example[]
|
||||||
|
@Any
|
||||||
|
@AnyKeyJavaClass( Integer.class )
|
||||||
|
@JoinColumn(name = "short_mixed_fk")
|
||||||
|
@Column(name = "short_mixed_type")
|
||||||
|
@AnyDiscriminatorImplicitValues(SHORT_NAME)
|
||||||
|
@AnyDiscriminatorValue( discriminator = "CARD", entity = CardPayment.class )
|
||||||
|
@AnyDiscriminatorValue( discriminator = "CHECK", entity = CheckPayment.class )
|
||||||
|
public Payment paymentMixedShortName;
|
||||||
|
//end::associations-any-mixed-discriminator-short-example[]
|
||||||
|
|
||||||
|
protected Order() {
|
||||||
|
// for Hibernate use
|
||||||
|
}
|
||||||
|
|
||||||
|
public Order(Integer id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,121 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
|
||||||
* Copyright Red Hat Inc. and Hibernate Authors
|
|
||||||
*/
|
|
||||||
package org.hibernate.orm.test.any.mixed;
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.assertj.core.api.Assertions.fail;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for {@link org.hibernate.type.AnyDiscriminatorValueStrategy}
|
|
||||||
*
|
|
||||||
* @author Steve Ebersole
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("JUnitMalformedDeclaration")
|
|
||||||
public class AnyDiscriminatorValueHandlingTests {
|
|
||||||
@Test
|
|
||||||
@DomainModel(annotatedClasses = {Payment.class, CashPayment.class, CardPayment.class, CheckPayment.class, Order.class})
|
|
||||||
@SessionFactory
|
|
||||||
void verifyImplicitMappingHandling(SessionFactoryScope sessions) {
|
|
||||||
sessions.inTransaction( (session) -> {
|
|
||||||
final Order order = new Order( 1, "1" );
|
|
||||||
final CashPayment cashPayment = new CashPayment( 1, 50.00 );
|
|
||||||
final CardPayment cardPayment = new CardPayment( 1, 150.00, "123-456-789" );
|
|
||||||
final CheckPayment checkPayment = new CheckPayment( 1, 250.00, 1001, "123", "987" );
|
|
||||||
session.persist( order );
|
|
||||||
session.persist( cashPayment );
|
|
||||||
session.persist( cardPayment );
|
|
||||||
session.persist( checkPayment );
|
|
||||||
session.flush();
|
|
||||||
|
|
||||||
order.implicitPayment = cardPayment;
|
|
||||||
session.flush();
|
|
||||||
|
|
||||||
order.implicitPayment = checkPayment;
|
|
||||||
session.flush();
|
|
||||||
|
|
||||||
order.implicitPayment = cashPayment;
|
|
||||||
session.flush();
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@DomainModel(annotatedClasses = {Payment.class, CashPayment.class, CardPayment.class, CheckPayment.class, Order.class})
|
|
||||||
@SessionFactory
|
|
||||||
void verifyExplicitMappingHandling(SessionFactoryScope sessions) {
|
|
||||||
sessions.inTransaction( (session) -> {
|
|
||||||
final Order order = new Order( 1, "1" );
|
|
||||||
final CashPayment cashPayment = new CashPayment( 1, 50.00 );
|
|
||||||
final CardPayment cardPayment = new CardPayment( 1, 150.00, "123-456-789" );
|
|
||||||
final CheckPayment checkPayment = new CheckPayment( 1, 250.00, 1001, "123", "987" );
|
|
||||||
session.persist( order );
|
|
||||||
session.persist( cashPayment );
|
|
||||||
session.persist( cardPayment );
|
|
||||||
session.persist( checkPayment );
|
|
||||||
session.flush();
|
|
||||||
|
|
||||||
order.explicitPayment = cardPayment;
|
|
||||||
session.flush();
|
|
||||||
|
|
||||||
order.explicitPayment = checkPayment;
|
|
||||||
session.flush();
|
|
||||||
|
|
||||||
// NOTE : cash is not explicitly mapped
|
|
||||||
try {
|
|
||||||
order.explicitPayment = cashPayment;
|
|
||||||
session.flush();
|
|
||||||
fail( "Expecting an error" );
|
|
||||||
}
|
|
||||||
catch (HibernateException expected) {
|
|
||||||
assertThat( expected ).hasMessageContaining( "Entity not explicitly mapped for ANY discriminator" );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@DomainModel(annotatedClasses = {Payment.class, CashPayment.class, CardPayment.class, CheckPayment.class, Order.class})
|
|
||||||
@SessionFactory
|
|
||||||
void verifyMixedMappingHandling(SessionFactoryScope sessions) {
|
|
||||||
sessions.inTransaction( (session) -> {
|
|
||||||
final Order order = new Order( 1, "1" );
|
|
||||||
final CashPayment cashPayment = new CashPayment( 1, 50.00 );
|
|
||||||
final CardPayment cardPayment = new CardPayment( 1, 150.00, "123-456-789" );
|
|
||||||
final CheckPayment checkPayment = new CheckPayment( 1, 250.00, 1001, "123", "987" );
|
|
||||||
session.persist( order );
|
|
||||||
session.persist( cashPayment );
|
|
||||||
session.persist( cardPayment );
|
|
||||||
session.persist( checkPayment );
|
|
||||||
session.flush();
|
|
||||||
|
|
||||||
order.mixedPayment = cardPayment;
|
|
||||||
session.flush();
|
|
||||||
|
|
||||||
order.mixedPayment = checkPayment;
|
|
||||||
session.flush();
|
|
||||||
|
|
||||||
order.mixedPayment = cashPayment;
|
|
||||||
session.flush();
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
@DomainModel(annotatedClasses = {Payment.class, CashPayment.class, CardPayment.class, CheckPayment.class, Order.class})
|
|
||||||
@SessionFactory
|
|
||||||
void dropTestData(SessionFactoryScope sessions) {
|
|
||||||
sessions.inTransaction( (session) -> {
|
|
||||||
session.createMutationQuery( "delete Order" ).executeUpdate();
|
|
||||||
session.createMutationQuery( "delete CashPayment" ).executeUpdate();
|
|
||||||
session.createMutationQuery( "delete CardPayment" ).executeUpdate();
|
|
||||||
session.createMutationQuery( "delete CheckPayment" ).executeUpdate();
|
|
||||||
} );
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,217 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
|
||||||
* Copyright Red Hat Inc. and Hibernate Authors
|
|
||||||
*/
|
|
||||||
package org.hibernate.orm.test.any.mixed;
|
|
||||||
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.metamodel.mapping.DiscriminatorConverter;
|
|
||||||
import org.hibernate.metamodel.mapping.DiscriminatorMapping;
|
|
||||||
import org.hibernate.metamodel.mapping.DiscriminatorValueDetails;
|
|
||||||
import org.hibernate.metamodel.mapping.internal.DiscriminatedAssociationAttributeMapping;
|
|
||||||
import org.hibernate.metamodel.mapping.internal.ExplicitDiscriminatorConverter;
|
|
||||||
import org.hibernate.metamodel.mapping.internal.ImplicitDiscriminatorConverter;
|
|
||||||
import org.hibernate.metamodel.mapping.internal.MixedDiscriminatorConverter;
|
|
||||||
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.hibernate.type.AnyDiscriminatorValueStrategy;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.assertj.core.api.Assertions.fail;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for {@link org.hibernate.type.AnyDiscriminatorValueStrategy}
|
|
||||||
*
|
|
||||||
* @author Steve Ebersole
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("JUnitMalformedDeclaration")
|
|
||||||
public class AnyDiscriminatorValueStrategyTests {
|
|
||||||
@Test
|
|
||||||
@DomainModel(annotatedClasses = {Payment.class, CashPayment.class, CardPayment.class, CheckPayment.class, Order.class})
|
|
||||||
@SessionFactory
|
|
||||||
void verifyImplicitMappingModel(SessionFactoryScope sessions) {
|
|
||||||
sessions.withSessionFactory( (factory) -> {
|
|
||||||
final EntityPersister entityDescriptor = factory.getMappingMetamodel().getEntityDescriptor( Order.class );
|
|
||||||
final DiscriminatedAssociationAttributeMapping implicitMapping = (DiscriminatedAssociationAttributeMapping) entityDescriptor.findAttributeMapping( "implicitPayment" );
|
|
||||||
final DiscriminatorMapping discriminatorMapping = implicitMapping.getDiscriminatorMapping();
|
|
||||||
final DiscriminatorConverter<?, ?> discriminatorConverter = discriminatorMapping.getValueConverter();
|
|
||||||
assertThat( discriminatorConverter.getValueStrategy() ).isEqualTo( AnyDiscriminatorValueStrategy.IMPLICIT );
|
|
||||||
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
// check discriminator -> entity
|
|
||||||
|
|
||||||
final DiscriminatorValueDetails cash = discriminatorConverter.getDetailsForDiscriminatorValue( CashPayment.class.getName() );
|
|
||||||
assertThat( cash.getIndicatedEntity().getEntityName() ).isEqualTo( CashPayment.class.getName() );
|
|
||||||
assertThat( cash.getIndicatedEntityName() ).isEqualTo( CashPayment.class.getName() );
|
|
||||||
|
|
||||||
final DiscriminatorValueDetails card = discriminatorConverter.getDetailsForDiscriminatorValue( CardPayment.class.getName() );
|
|
||||||
assertThat( card.getIndicatedEntity().getEntityName() ).isEqualTo( CardPayment.class.getName() );
|
|
||||||
assertThat( card.getIndicatedEntityName() ).isEqualTo( CardPayment.class.getName() );
|
|
||||||
|
|
||||||
final DiscriminatorValueDetails check = discriminatorConverter.getDetailsForDiscriminatorValue( CheckPayment.class.getName() );
|
|
||||||
assertThat( check.getIndicatedEntity().getEntityName() ).isEqualTo( CheckPayment.class.getName() );
|
|
||||||
assertThat( check.getIndicatedEntityName() ).isEqualTo( CheckPayment.class.getName() );
|
|
||||||
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
// check entity -> discriminator
|
|
||||||
|
|
||||||
final DiscriminatorValueDetails cashDiscriminatorValue = discriminatorConverter.getDetailsForEntityName( CashPayment.class.getName() );
|
|
||||||
assertThat( cashDiscriminatorValue.getValue() ).isEqualTo( CashPayment.class.getName() );
|
|
||||||
|
|
||||||
final DiscriminatorValueDetails cardDiscriminatorValue = discriminatorConverter.getDetailsForEntityName( CardPayment.class.getName() );
|
|
||||||
assertThat( cardDiscriminatorValue.getValue() ).isEqualTo( CardPayment.class.getName() );
|
|
||||||
|
|
||||||
final DiscriminatorValueDetails checkDiscriminatorValue = discriminatorConverter.getDetailsForEntityName( CheckPayment.class.getName() );
|
|
||||||
assertThat( checkDiscriminatorValue.getValue() ).isEqualTo( CheckPayment.class.getName() );
|
|
||||||
|
|
||||||
final Map<String,?> detailsByEntityName = ((ImplicitDiscriminatorConverter<?,?>) discriminatorConverter).getDetailsByEntityName();
|
|
||||||
assertThat( detailsByEntityName.keySet() ).containsOnly(
|
|
||||||
CashPayment.class.getName(),
|
|
||||||
CardPayment.class.getName(),
|
|
||||||
CheckPayment.class.getName()
|
|
||||||
);
|
|
||||||
|
|
||||||
final Map<Object,?> detailsByValue = ((ImplicitDiscriminatorConverter<?,?>) discriminatorConverter).getDetailsByValue();
|
|
||||||
assertThat( detailsByValue.keySet() ).containsOnly(
|
|
||||||
CashPayment.class.getName(),
|
|
||||||
CardPayment.class.getName(),
|
|
||||||
CheckPayment.class.getName()
|
|
||||||
);
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@DomainModel(annotatedClasses = {Payment.class, CashPayment.class, CardPayment.class, CheckPayment.class, Order.class})
|
|
||||||
@SessionFactory
|
|
||||||
void verifyExplicitMappingModel(SessionFactoryScope sessions) {
|
|
||||||
sessions.withSessionFactory( (factory) -> {
|
|
||||||
final EntityPersister entityDescriptor = factory.getMappingMetamodel().getEntityDescriptor( Order.class );
|
|
||||||
final DiscriminatedAssociationAttributeMapping explicitMapping = (DiscriminatedAssociationAttributeMapping) entityDescriptor.findAttributeMapping( "explicitPayment" );
|
|
||||||
final DiscriminatorMapping discriminatorMapping = explicitMapping.getDiscriminatorMapping();
|
|
||||||
final DiscriminatorConverter<?, ?> discriminatorConverter = discriminatorMapping.getValueConverter();
|
|
||||||
assertThat( discriminatorConverter.getValueStrategy() ).isEqualTo( AnyDiscriminatorValueStrategy.EXPLICIT );
|
|
||||||
|
|
||||||
// NOTE : cash is NOT mapped
|
|
||||||
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
// check discriminator -> entity
|
|
||||||
|
|
||||||
try {
|
|
||||||
discriminatorConverter.getDetailsForDiscriminatorValue( "CASH" );
|
|
||||||
fail( "Expecting an error" );
|
|
||||||
}
|
|
||||||
catch (HibernateException expected) {
|
|
||||||
assertThat( expected ).hasMessageContaining( "Unknown discriminator value" );
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
discriminatorConverter.getDetailsForDiscriminatorValue( CashPayment.class.getName() );
|
|
||||||
fail( "Expecting an error" );
|
|
||||||
}
|
|
||||||
catch (HibernateException expected) {
|
|
||||||
assertThat( expected ).hasMessageContaining( "Unknown discriminator value" );
|
|
||||||
}
|
|
||||||
|
|
||||||
final DiscriminatorValueDetails card = discriminatorConverter.getDetailsForDiscriminatorValue( "CARD" );
|
|
||||||
assertThat( card.getIndicatedEntity().getEntityName() ).isEqualTo( CardPayment.class.getName() );
|
|
||||||
assertThat( card.getIndicatedEntityName() ).isEqualTo( CardPayment.class.getName() );
|
|
||||||
|
|
||||||
final DiscriminatorValueDetails check = discriminatorConverter.getDetailsForDiscriminatorValue( "CHECK" );
|
|
||||||
assertThat( check.getIndicatedEntity().getEntityName() ).isEqualTo( CheckPayment.class.getName() );
|
|
||||||
assertThat( check.getIndicatedEntityName() ).isEqualTo( CheckPayment.class.getName() );
|
|
||||||
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
// check entity -> discriminator
|
|
||||||
|
|
||||||
try {
|
|
||||||
discriminatorConverter.getDetailsForDiscriminatorValue( CashPayment.class.getName() );
|
|
||||||
fail( "Expecting an error" );
|
|
||||||
}
|
|
||||||
catch (HibernateException expected) {
|
|
||||||
assertThat( expected ).hasMessageContaining( "Unknown discriminator value" );
|
|
||||||
}
|
|
||||||
|
|
||||||
final DiscriminatorValueDetails cardDiscriminatorValue = discriminatorConverter.getDetailsForEntityName( CardPayment.class.getName() );
|
|
||||||
assertThat( cardDiscriminatorValue.getValue() ).isEqualTo( "CARD" );
|
|
||||||
|
|
||||||
final DiscriminatorValueDetails checkDiscriminatorValue = discriminatorConverter.getDetailsForEntityName( CheckPayment.class.getName() );
|
|
||||||
assertThat( checkDiscriminatorValue.getValue() ).isEqualTo( "CHECK" );
|
|
||||||
|
|
||||||
|
|
||||||
final Map<String,?> detailsByEntityName = ((ExplicitDiscriminatorConverter<?,?>) discriminatorConverter).getDetailsByEntityName();
|
|
||||||
assertThat( detailsByEntityName.keySet() ).containsOnly(
|
|
||||||
CardPayment.class.getName(),
|
|
||||||
CheckPayment.class.getName()
|
|
||||||
);
|
|
||||||
|
|
||||||
final Map<Object,?> detailsByValue = ((ExplicitDiscriminatorConverter<?,?>) discriminatorConverter).getDetailsByValue();
|
|
||||||
assertThat( detailsByValue.keySet() ).containsOnly(
|
|
||||||
"CARD",
|
|
||||||
"CHECK"
|
|
||||||
);
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@DomainModel(annotatedClasses = {Payment.class, CashPayment.class, CardPayment.class, CheckPayment.class, Order.class})
|
|
||||||
@SessionFactory
|
|
||||||
void verifyMixedMappingModel(SessionFactoryScope sessions) {
|
|
||||||
sessions.withSessionFactory( (factory) -> {
|
|
||||||
final EntityPersister entityDescriptor = factory.getMappingMetamodel().getEntityDescriptor( Order.class );
|
|
||||||
final DiscriminatedAssociationAttributeMapping mixedMapping = (DiscriminatedAssociationAttributeMapping) entityDescriptor.findAttributeMapping( "mixedPayment" );
|
|
||||||
final DiscriminatorMapping discriminatorMapping = mixedMapping.getDiscriminatorMapping();
|
|
||||||
final DiscriminatorConverter<?, ?> discriminatorConverter = discriminatorMapping.getValueConverter();
|
|
||||||
// historically this operated as if EXPLICIT
|
|
||||||
assertThat( discriminatorConverter.getValueStrategy() ).isEqualTo( AnyDiscriminatorValueStrategy.MIXED );
|
|
||||||
|
|
||||||
// NOTE : cash is NOT mapped
|
|
||||||
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
// check discriminator -> entity
|
|
||||||
|
|
||||||
final DiscriminatorValueDetails cash = discriminatorConverter.getDetailsForDiscriminatorValue( CashPayment.class.getName() );
|
|
||||||
assertThat( cash.getIndicatedEntity().getEntityName() ).isEqualTo( CashPayment.class.getName() );
|
|
||||||
assertThat( cash.getIndicatedEntityName() ).isEqualTo( CashPayment.class.getName() );
|
|
||||||
|
|
||||||
final DiscriminatorValueDetails card = discriminatorConverter.getDetailsForDiscriminatorValue( "CARD" );
|
|
||||||
assertThat( card.getIndicatedEntity().getEntityName() ).isEqualTo( CardPayment.class.getName() );
|
|
||||||
assertThat( card.getIndicatedEntityName() ).isEqualTo( CardPayment.class.getName() );
|
|
||||||
|
|
||||||
final DiscriminatorValueDetails check = discriminatorConverter.getDetailsForDiscriminatorValue( "CHECK" );
|
|
||||||
assertThat( check.getIndicatedEntity().getEntityName() ).isEqualTo( CheckPayment.class.getName() );
|
|
||||||
assertThat( check.getIndicatedEntityName() ).isEqualTo( CheckPayment.class.getName() );
|
|
||||||
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
// check entity -> discriminator
|
|
||||||
|
|
||||||
final DiscriminatorValueDetails cashDiscriminatorValue = discriminatorConverter.getDetailsForEntityName( CashPayment.class.getName() );
|
|
||||||
assertThat( cashDiscriminatorValue.getValue() ).isEqualTo( CashPayment.class.getName() );
|
|
||||||
|
|
||||||
final DiscriminatorValueDetails cardDiscriminatorValue = discriminatorConverter.getDetailsForEntityName( CardPayment.class.getName() );
|
|
||||||
assertThat( cardDiscriminatorValue.getValue() ).isEqualTo( "CARD" );
|
|
||||||
|
|
||||||
final DiscriminatorValueDetails checkDiscriminatorValue = discriminatorConverter.getDetailsForEntityName( CheckPayment.class.getName() );
|
|
||||||
assertThat( checkDiscriminatorValue.getValue() ).isEqualTo( "CHECK" );
|
|
||||||
|
|
||||||
final Map<String,?> detailsByEntityName = ((MixedDiscriminatorConverter<?,?>) discriminatorConverter).getDetailsByEntityName();
|
|
||||||
assertThat( detailsByEntityName.keySet() ).containsOnly(
|
|
||||||
CashPayment.class.getName(),
|
|
||||||
CardPayment.class.getName(),
|
|
||||||
CheckPayment.class.getName()
|
|
||||||
);
|
|
||||||
|
|
||||||
final Map<Object,?> detailsByValue = ((MixedDiscriminatorConverter<?,?>) discriminatorConverter).getDetailsByValue();
|
|
||||||
assertThat( detailsByValue.keySet() ).containsOnly(
|
|
||||||
CashPayment.class.getName(),
|
|
||||||
"CARD",
|
|
||||||
"CHECK"
|
|
||||||
);
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
|
||||||
* Copyright Red Hat Inc. and Hibernate Authors
|
|
||||||
*/
|
|
||||||
package org.hibernate.orm.test.any.mixed;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Steve Ebersole
|
|
||||||
*/
|
|
||||||
public interface Payment {
|
|
||||||
Double getAmount();
|
|
||||||
}
|
|
Loading…
Reference in New Issue