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: ../../../../../../..
|
||||
:core-project-dir: {root-project-dir}/hibernate-core
|
||||
: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
|
||||
|
||||
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,
|
||||
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]
|
||||
====
|
||||
|
@ -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:
|
||||
|
||||
1. The column and mapping for the discriminator
|
||||
2. The column and mapping for the key
|
||||
3. The mapping between discriminator values and entity classes
|
||||
1. The column and mapping for the <<associations-any-discriminator,discriminator>>
|
||||
2. The column and mapping for the <<associations-any-key,key>>
|
||||
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]]
|
||||
===== The discriminator
|
||||
|
||||
The discriminator of an any-style association holds the value that indicates which entity is
|
||||
referred to by a row.
|
||||
The discriminator is the value that indicates which entity is referred to by a row.
|
||||
|
||||
Its "column" can be specified with either `@Column` or `@Formula`. The mapping type can be influenced by any of:
|
||||
|
||||
|
@ -601,114 +619,105 @@ type can be influenced by any of:
|
|||
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]]
|
||||
==== Example using @Any mapping
|
||||
|
||||
For this example, consider the following `Property` class hierarchy:
|
||||
|
||||
[[associations-any-property-example]]
|
||||
.`Property` class hierarchy
|
||||
[[associations-any-discriminator-explicit-example]]
|
||||
.Explicit @AnyDiscriminatorValue annotations
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{example-dir-association}/any/Property.java[tags=associations-any-property-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]
|
||||
include::{example-dir-any}/discriminator/explicit/Order.java[tags=associations-any-explicit-discriminator-example]
|
||||
----
|
||||
====
|
||||
|
||||
A `PropertyHolder` entity defines an attribute of type `Property`:
|
||||
Here, we map 2 explicit discriminator value mappings:
|
||||
|
||||
[[associations-any-example]]
|
||||
.`@Any` mapping usage
|
||||
1. `CARD` <-> `CardPayment`
|
||||
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]
|
||||
----
|
||||
include::{example-dir-association}/any/PropertyHolder.java[tags=associations-any-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{extrasdir}/associations-any-example.sql[]
|
||||
include::{example-dir-any}/discriminator/implicit/Order.java[tags=associations-any-implicit-discriminator-example]
|
||||
----
|
||||
====
|
||||
|
||||
`PropertyHolder#property` can refer to either `StringProperty` or `IntegerProperty` references, as indicated
|
||||
by the associated discriminator according to the `@DiscriminatorValue` annotations.
|
||||
Here all `Payment` subtypes are allowed. By default Hibernate will use the entity's full-name (which is generally the class's FQN).
|
||||
|
||||
As you can see, there are two columns used to reference a `Property` instance: `property_id` and `property_type`.
|
||||
The `property_id` is used to match the `id` column of either the `string_property` or `integer_property` tables,
|
||||
while the `property_type` is used to match the `string_property` or the `integer_property` table.
|
||||
Hibernate also offers a `@AnyDiscriminatorImplicitValues` annotation which allows configuration of how this implicit
|
||||
mapping works. E.g., to use the entity's short-name instead of the full-name -
|
||||
|
||||
To see the `@Any` annotation in action, consider the next examples.
|
||||
|
||||
If we persist an `IntegerProperty` as well as a `StringProperty` entity, and associate
|
||||
the `StringProperty` entity with a `PropertyHolder`,
|
||||
Hibernate will generate the following SQL queries:
|
||||
|
||||
[[associations-any-persist-example]]
|
||||
.`@Any` mapping persist example
|
||||
[[associations-any-discriminator-implicit-short-example]]
|
||||
.Implicit @Any discriminator mappings (short name)
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{example-dir-association}/any/AnyTest.java[tags=associations-any-persist-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{extrasdir}/associations-any-persist-example.sql[]
|
||||
include::{example-dir-any}/discriminator/implicit/Order.java[tags=associations-any-implicit-discriminator-short-example]
|
||||
----
|
||||
====
|
||||
|
||||
When fetching the `PropertyHolder` entity and navigating its `property` association,
|
||||
Hibernate will fetch the associated `StringProperty` entity like this:
|
||||
[NOTE]
|
||||
====
|
||||
`@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]
|
||||
----
|
||||
include::{example-dir-association}/any/AnyTest.java[tags=associations-any-query-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{extrasdir}/associations-any-query-example.sql[]
|
||||
include::{example-dir-any}/discriminator/mixed/Order.java[tags=associations-any-mixed-discriminator-short-example]
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
|
||||
[[associations-any-meta-annotations]]
|
||||
===== Using meta-annotations
|
||||
|
||||
As mentioned in <<basic-mapping>>, Hibernate's ANY-related annotations can be composed using meta-annotations
|
||||
to re-use ANY mapping details.
|
||||
|
||||
Looking back at <<associations-any-example>>, we can see how cumbersome it would be to duplicate that
|
||||
information every time `Property` is mapped in the domain model. This description can also be moved
|
||||
Given all the details needed to define an ANY mapping, we can see how cumbersome it would be to duplicate that
|
||||
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.
|
||||
|
||||
|
||||
[[associations-any-composed-example]]
|
||||
.`@Any` mapping usage
|
||||
.`@Any` mapping with meta-annotation
|
||||
====
|
||||
[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]]
|
||||
|
@ -724,16 +733,16 @@ The mapping details are the same between `@Any` and `@ManyToAny` except for:
|
|||
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]]
|
||||
.`@ManyToAny` mapping usage
|
||||
====
|
||||
[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]
|
||||
|
@ -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]]
|
||||
|
|
|
@ -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,
|
||||
...,
|
||||
PRIMARY KEY ( id )
|
||||
)
|
||||
|
||||
CREATE TABLE repository_properties (
|
||||
repository_id BIGINT NOT NULL,
|
||||
property_type VARCHAR(255),
|
||||
property_id BIGINT NOT NULL
|
||||
CREATE TABLE loan_payments (
|
||||
loan_fk BIGINT NOT NULL,
|
||||
payment_type VARCHAR(255),
|
||||
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;
|
||||
|
||||
import jakarta.persistence.DiscriminatorType;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
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.FIELD;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
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}
|
||||
|
@ -34,6 +32,8 @@ import static org.hibernate.type.AnyDiscriminatorValueStrategy.AUTO;
|
|||
* {@code @AnyDiscriminator}.
|
||||
*
|
||||
* @see Any
|
||||
* @see AnyDiscriminatorValue
|
||||
* @see AnyDiscriminatorImplicitValues
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
|
@ -46,12 +46,4 @@ public @interface AnyDiscriminator {
|
|||
* or {@link JdbcTypeCode}.
|
||||
*/
|
||||
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 AnyDiscriminator
|
||||
* @see AnyDiscriminatorImplicitValues
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
|
|
|
@ -9,6 +9,7 @@ import java.util.Locale;
|
|||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.annotations.AnyDiscriminator;
|
||||
import org.hibernate.annotations.AnyDiscriminatorImplicitValues;
|
||||
import org.hibernate.annotations.Cascade;
|
||||
import org.hibernate.annotations.Columns;
|
||||
import org.hibernate.annotations.Formula;
|
||||
|
@ -19,6 +20,9 @@ import org.hibernate.boot.spi.PropertyData;
|
|||
import org.hibernate.mapping.Any;
|
||||
import org.hibernate.mapping.Join;
|
||||
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 jakarta.persistence.Column;
|
||||
|
@ -109,8 +113,9 @@ public class AnyBinder {
|
|||
);
|
||||
|
||||
final AnyDiscriminator anyDiscriminator = property.getDirectAnnotationUsage( AnyDiscriminator.class );
|
||||
if ( anyDiscriminator != null ) {
|
||||
value.setDiscriminatorValueStrategy( anyDiscriminator.valueStrategy() );
|
||||
final AnyDiscriminatorImplicitValues anyDiscriminatorImplicitValues = property.getDirectAnnotationUsage( AnyDiscriminatorImplicitValues.class );
|
||||
if ( anyDiscriminatorImplicitValues != null ) {
|
||||
value.setImplicitDiscriminatorValueStrategy( resolveImplicitDiscriminatorStrategy( anyDiscriminatorImplicitValues, context ) );
|
||||
}
|
||||
|
||||
final PropertyBinder binder = new PropertyBinder();
|
||||
|
@ -134,4 +139,36 @@ public class AnyBinder {
|
|||
propertyHolder.addProperty( prop, inferredData.getAttributeMember(), columns, inferredData.getDeclaringClass() );
|
||||
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.FetchMode;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.annotations.AnyDiscriminatorImplicitValues;
|
||||
import org.hibernate.annotations.AnyDiscriminatorValue;
|
||||
import org.hibernate.annotations.AnyDiscriminatorValues;
|
||||
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.PROVIDER_DEFAULT;
|
||||
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.isNotEmpty;
|
||||
import static org.hibernate.internal.util.StringHelper.qualifier;
|
||||
|
@ -806,6 +808,12 @@ public class BinderHelper {
|
|||
);
|
||||
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 List<AnnotatedJoinColumn> columns = keyColumns.getJoinColumns();
|
||||
assert columns.size() == 1;
|
||||
|
|
|
@ -36,6 +36,10 @@ public interface HibernateAnnotations {
|
|||
AnyDiscriminator.class,
|
||||
AnyDiscriminatorAnnotation.class
|
||||
);
|
||||
OrmAnnotationDescriptor<AnyDiscriminatorImplicitValues,AnyDiscriminatorImplicitValuesAnnotation> ANY_DISCRIMINATOR_IMPLICIT_VALUES = new OrmAnnotationDescriptor<>(
|
||||
AnyDiscriminatorImplicitValues.class,
|
||||
AnyDiscriminatorImplicitValuesAnnotation.class
|
||||
);
|
||||
OrmAnnotationDescriptor<AnyDiscriminatorValues,AnyDiscriminatorValuesAnnotation> ANY_DISCRIMINATOR_VALUES = new OrmAnnotationDescriptor<>(
|
||||
AnyDiscriminatorValues.class,
|
||||
AnyDiscriminatorValuesAnnotation.class
|
||||
|
|
|
@ -4,25 +4,22 @@
|
|||
*/
|
||||
package org.hibernate.boot.models.annotations.internal;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.annotations.AnyDiscriminator;
|
||||
import org.hibernate.models.spi.SourceModelBuildingContext;
|
||||
import org.hibernate.type.AnyDiscriminatorValueStrategy;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings({ "ClassExplicitlyAnnotation", "unused" })
|
||||
@jakarta.annotation.Generated("org.hibernate.orm.build.annotations.ClassGeneratorProcessor")
|
||||
public class AnyDiscriminatorAnnotation implements AnyDiscriminator {
|
||||
private jakarta.persistence.DiscriminatorType value;
|
||||
private AnyDiscriminatorValueStrategy valueStrategy;
|
||||
|
||||
/**
|
||||
* Used in creating dynamic annotation instances (e.g. from XML)
|
||||
*/
|
||||
public AnyDiscriminatorAnnotation(SourceModelBuildingContext modelContext) {
|
||||
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) {
|
||||
this.value = annotation.value();
|
||||
this.valueStrategy = annotation.valueStrategy();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -53,15 +49,4 @@ public class AnyDiscriminatorAnnotation implements AnyDiscriminator {
|
|||
public void value(jakarta.persistence.DiscriminatorType 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;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
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.Type;
|
||||
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}
|
||||
|
@ -35,7 +35,7 @@ public class Any extends SimpleValue {
|
|||
|
||||
// common
|
||||
private Map<Object,String> metaValueToEntityNameMap;
|
||||
private AnyDiscriminatorValueStrategy discriminatorValueStrategy = AnyDiscriminatorValueStrategy.AUTO;
|
||||
private ImplicitDiscriminatorStrategy implicitValueStrategy;
|
||||
private boolean lazy = true;
|
||||
|
||||
private AnyType resolvedType;
|
||||
|
@ -75,7 +75,7 @@ public class Any extends SimpleValue {
|
|||
this.metaValueToEntityNameMap = original.metaValueToEntityNameMap == null
|
||||
? null
|
||||
: new HashMap<>(original.metaValueToEntityNameMap);
|
||||
this.discriminatorValueStrategy = original.discriminatorValueStrategy;
|
||||
this.implicitValueStrategy = original.implicitValueStrategy;
|
||||
this.lazy = original.lazy;
|
||||
}
|
||||
|
||||
|
@ -131,28 +131,6 @@ public class Any extends SimpleValue {
|
|||
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
|
||||
public AnyType getType() throws MappingException {
|
||||
if ( resolvedType == null ) {
|
||||
|
@ -175,8 +153,8 @@ public class Any extends SimpleValue {
|
|||
resolvedType = MappingHelper.anyMapping(
|
||||
discriminatorType,
|
||||
identifierType,
|
||||
discriminatorValueStrategy,
|
||||
metaValueToEntityNameMap,
|
||||
implicitValueStrategy,
|
||||
isLazy(),
|
||||
getBuildingContext()
|
||||
);
|
||||
|
@ -242,6 +220,19 @@ public class Any extends SimpleValue {
|
|||
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() {
|
||||
return lazy;
|
||||
}
|
||||
|
@ -334,7 +325,6 @@ public class Any extends SimpleValue {
|
|||
public static class MetaValue extends SimpleValue {
|
||||
private String typeName;
|
||||
private String columnName;
|
||||
private AnyDiscriminatorValueStrategy valueStrategy;
|
||||
|
||||
private final Consumer<Selectable> selectableConsumer;
|
||||
|
||||
|
@ -427,10 +417,6 @@ public class Any extends SimpleValue {
|
|||
return columnName != null
|
||||
&& getType().getColumnSpan( mappingContext ) == 1;
|
||||
}
|
||||
|
||||
public AnyDiscriminatorValueStrategy getValueStrategy() {
|
||||
return valueStrategy;
|
||||
}
|
||||
}
|
||||
|
||||
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.MetadataImplementor;
|
||||
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.spi.ManagedBean;
|
||||
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
|
||||
import org.hibernate.resource.beans.spi.ProvidedInstanceManagedBeanImpl;
|
||||
import org.hibernate.type.AnyDiscriminatorValueStrategy;
|
||||
import org.hibernate.type.AnyType;
|
||||
import org.hibernate.type.CollectionType;
|
||||
import org.hibernate.type.CustomCollectionType;
|
||||
|
@ -129,17 +129,24 @@ public final class MappingHelper {
|
|||
Map<Object, String> explicitValeMappings,
|
||||
boolean lazy,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
return anyMapping( discriminatorType, identifierType, AnyDiscriminatorValueStrategy.AUTO, explicitValeMappings, lazy, buildingContext );
|
||||
return anyMapping(
|
||||
discriminatorType,
|
||||
identifierType,
|
||||
explicitValeMappings,
|
||||
null,
|
||||
lazy,
|
||||
buildingContext
|
||||
);
|
||||
}
|
||||
|
||||
public static AnyType anyMapping(
|
||||
Type discriminatorType,
|
||||
Type identifierType,
|
||||
AnyDiscriminatorValueStrategy discriminatorValueStrategy,
|
||||
Map<Object, String> explicitValeMappings,
|
||||
ImplicitDiscriminatorStrategy implicitValueStrategy,
|
||||
boolean lazy,
|
||||
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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.metamodel.RepresentationMode;
|
||||
import org.hibernate.type.AnyDiscriminatorValueStrategy;
|
||||
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
|
||||
|
@ -31,9 +29,6 @@ public abstract class DiscriminatorConverter<O,R> implements BasicValueConverter
|
|||
this.relationalJavaType = relationalJavaType;
|
||||
}
|
||||
|
||||
@Incubating
|
||||
public abstract AnyDiscriminatorValueStrategy getValueStrategy();
|
||||
|
||||
public String getDiscriminatorName() {
|
||||
return discriminatorName;
|
||||
}
|
||||
|
@ -90,7 +85,7 @@ public abstract class DiscriminatorConverter<O,R> implements BasicValueConverter
|
|||
return (R) discriminatorValueDetails.getValue();
|
||||
}
|
||||
|
||||
public abstract DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relationalForm);
|
||||
public abstract DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relationalValue);
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* Find and return the first DiscriminatorValueDetails which matches the given {@code 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.metamodel.mapping.internal.EmbeddableDiscriminatorValueDetailsImpl;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.type.AnyDiscriminatorValueStrategy;
|
||||
import org.hibernate.type.BasicType;
|
||||
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
|
||||
public O toDomainValue(R relationalForm) {
|
||||
assert relationalForm == null || getRelationalJavaType().isInstance( relationalForm );
|
||||
|
@ -86,13 +79,13 @@ public class EmbeddableDiscriminatorConverter<O, R> extends DiscriminatorConvert
|
|||
}
|
||||
|
||||
@Override
|
||||
public EmbeddableDiscriminatorValueDetailsImpl getDetailsForDiscriminatorValue(Object value) {
|
||||
final EmbeddableDiscriminatorValueDetailsImpl valueMatch = discriminatorValueToDetailsMap.get( value );
|
||||
public EmbeddableDiscriminatorValueDetailsImpl getDetailsForDiscriminatorValue(Object relationalValue) {
|
||||
final EmbeddableDiscriminatorValueDetailsImpl valueMatch = discriminatorValueToDetailsMap.get( relationalValue );
|
||||
if ( valueMatch != null ) {
|
||||
return valueMatch;
|
||||
}
|
||||
|
||||
throw new HibernateException( "Unrecognized discriminator value: " + value );
|
||||
throw new HibernateException( "Unrecognized discriminator value: " + relationalValue );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -462,6 +462,10 @@ public interface EntityMappingType
|
|||
|
||||
void visitConstraintOrderedTables(ConstraintOrderedTableConsumer consumer);
|
||||
|
||||
default String getImportedName() {
|
||||
return getEntityPersister().getImportedName();
|
||||
}
|
||||
|
||||
interface ConstraintOrderedTableConsumer {
|
||||
void consume(String tableExpression, Supplier<Consumer<SelectableConsumer>> tableKeyColumnVisitationSupplier);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.mapping.internal;
|
||||
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.cache.MutableCacheKeyBuilder;
|
||||
import org.hibernate.engine.FetchStyle;
|
||||
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.SelectableConsumer;
|
||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
import org.hibernate.metamodel.spi.ImplicitDiscriminatorStrategy;
|
||||
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
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.basic.BasicFetch;
|
||||
import org.hibernate.sql.results.graph.basic.BasicResult;
|
||||
import org.hibernate.type.AnyDiscriminatorValueStrategy;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.descriptor.java.ClassJavaType;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
|
@ -84,7 +83,7 @@ public class AnyDiscriminatorPart implements DiscriminatorMapping, FetchOptions
|
|||
boolean partitioned,
|
||||
BasicType<?> underlyingJdbcMapping,
|
||||
Map<Object,String> valueToEntityNameMap,
|
||||
AnyDiscriminatorValueStrategy valueStrategy,
|
||||
ImplicitDiscriminatorStrategy implicitValueStrategy,
|
||||
MappingMetamodelImplementor mappingMetamodel) {
|
||||
this.navigableRole = partRole;
|
||||
this.declaringType = declaringType;
|
||||
|
@ -105,7 +104,7 @@ public class AnyDiscriminatorPart implements DiscriminatorMapping, FetchOptions
|
|||
partRole,
|
||||
underlyingJdbcMapping,
|
||||
valueToEntityNameMap,
|
||||
valueStrategy,
|
||||
implicitValueStrategy,
|
||||
mappingMetamodel
|
||||
);
|
||||
}
|
||||
|
@ -114,41 +113,16 @@ public class AnyDiscriminatorPart implements DiscriminatorMapping, FetchOptions
|
|||
NavigableRole partRole,
|
||||
BasicType<?> underlyingJdbcMapping,
|
||||
Map<Object, String> valueToEntityNameMap,
|
||||
AnyDiscriminatorValueStrategy valueStrategy,
|
||||
ImplicitDiscriminatorStrategy implicitValueStrategy,
|
||||
MappingMetamodelImplementor mappingMetamodel) {
|
||||
if ( valueStrategy == AnyDiscriminatorValueStrategy.AUTO ) {
|
||||
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<>(
|
||||
return new UnifiedAnyDiscriminatorConverter<>(
|
||||
partRole,
|
||||
ClassJavaType.INSTANCE,
|
||||
underlyingJdbcMapping.getJavaTypeDescriptor(),
|
||||
valueToEntityNameMap,
|
||||
implicitValueStrategy,
|
||||
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() {
|
||||
|
|
|
@ -89,7 +89,7 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
|
|||
bootValueMapping.isPartitionKey(),
|
||||
(BasicType<?>) metaType.getBaseType(),
|
||||
metaType.getDiscriminatorValuesToEntityNameMap(),
|
||||
metaType.getValueStrategy(),
|
||||
metaType.getImplicitValueStrategy(),
|
||||
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.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.metamodel.internal.FullNameImplicitDiscriminatorStrategy;
|
||||
import org.hibernate.metamodel.mapping.DiscriminatorConverter;
|
||||
import org.hibernate.metamodel.mapping.DiscriminatorValueDetails;
|
||||
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;
|
||||
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;
|
||||
|
@ -24,45 +26,59 @@ import static org.hibernate.persister.entity.DiscriminatorHelper.NOT_NULL_DISCRI
|
|||
import static org.hibernate.persister.entity.DiscriminatorHelper.NULL_DISCRIMINATOR;
|
||||
|
||||
/**
|
||||
* DiscriminatorConverter for use with {@linkplain org.hibernate.type.AnyDiscriminatorValueStrategy#MIXED}
|
||||
*
|
||||
* @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 Map<Object, DiscriminatorValueDetails> detailsByValue;
|
||||
private final Map<String,DiscriminatorValueDetails> detailsByEntityName;
|
||||
private final ImplicitDiscriminatorStrategy implicitValueStrategy;
|
||||
private final MappingMetamodelImplementor mappingMetamodel;
|
||||
|
||||
public MixedDiscriminatorConverter(
|
||||
public UnifiedAnyDiscriminatorConverter(
|
||||
NavigableRole discriminatorRole,
|
||||
JavaType<O> domainJavaType,
|
||||
JavaType<R> relationalJavaType,
|
||||
Map<Object,String> explicitValueMappings,
|
||||
ImplicitDiscriminatorStrategy implicitValueStrategy,
|
||||
MappingMetamodelImplementor mappingMetamodel) {
|
||||
super( discriminatorRole.getFullPath(), domainJavaType, relationalJavaType );
|
||||
this.discriminatorRole = discriminatorRole;
|
||||
this.mappingMetamodel = mappingMetamodel;
|
||||
|
||||
this.implicitValueStrategy = resolveImplicitValueStrategy( implicitValueStrategy, explicitValueMappings );
|
||||
|
||||
this.detailsByValue = CollectionHelper.concurrentMap( explicitValueMappings.size() );
|
||||
this.detailsByEntityName = CollectionHelper.concurrentMap( explicitValueMappings.size() );
|
||||
explicitValueMappings.forEach( (value,entityName) -> {
|
||||
String importedEntityName = mappingMetamodel.getImportedName( entityName );
|
||||
final EntityPersister entityDescriptor = mappingMetamodel.getEntityDescriptor( importedEntityName );
|
||||
register( value, entityDescriptor );
|
||||
final String importedEntityName = mappingMetamodel.getImportedName( entityName );
|
||||
final EntityPersister entityMapping = mappingMetamodel.getEntityDescriptor( importedEntityName );
|
||||
register( value, entityMapping );
|
||||
} );
|
||||
}
|
||||
|
||||
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;
|
||||
private ImplicitDiscriminatorStrategy resolveImplicitValueStrategy(ImplicitDiscriminatorStrategy implicitValueStrategy, Map<Object, String> explicitValueMappings) {
|
||||
if ( explicitValueMappings.isEmpty() ) {
|
||||
if ( implicitValueStrategy == null ) {
|
||||
return FullNameImplicitDiscriminatorStrategy.FULL_NAME_STRATEGY;
|
||||
}
|
||||
}
|
||||
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
|
||||
public AnyDiscriminatorValueStrategy getValueStrategy() {
|
||||
return AnyDiscriminatorValueStrategy.MIXED;
|
||||
private DiscriminatorValueDetails register(Object value, EntityMappingType entityMapping) {
|
||||
final DiscriminatorValueDetails details = new DiscriminatorValueDetailsImpl( value, entityMapping );
|
||||
detailsByValue.put( value, details );
|
||||
detailsByEntityName.put( entityMapping.getEntityName(), details );
|
||||
return details;
|
||||
}
|
||||
|
||||
public Map<Object, DiscriminatorValueDetails> getDetailsByValue() {
|
||||
|
@ -74,32 +90,26 @@ public class MixedDiscriminatorConverter<O,R> extends DiscriminatorConverter<O,R
|
|||
}
|
||||
|
||||
@Override
|
||||
public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relationalForm) {
|
||||
if ( relationalForm == null ) {
|
||||
public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relationalValue) {
|
||||
if ( relationalValue == null ) {
|
||||
return detailsByValue.get( NULL_DISCRIMINATOR );
|
||||
}
|
||||
|
||||
final DiscriminatorValueDetails existing = detailsByValue.get( relationalForm );
|
||||
final DiscriminatorValueDetails existing = detailsByValue.get( relationalValue );
|
||||
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() ) {
|
||||
if ( relationalValue.getClass().isEnum() ) {
|
||||
final Object enumValue;
|
||||
if ( getRelationalJavaType() instanceof StringJavaType ) {
|
||||
enumValue = ( (Enum<?>) relationalForm ).name();
|
||||
enumValue = ( (Enum<?>) relationalValue ).name();
|
||||
}
|
||||
else if ( getRelationalJavaType() instanceof CharacterJavaType ) {
|
||||
enumValue = ( (Enum<?>) relationalForm ).name().charAt( 0 );
|
||||
enumValue = ( (Enum<?>) relationalValue ).name().charAt( 0 );
|
||||
}
|
||||
else {
|
||||
enumValue = ( (Enum<?>) relationalForm ).ordinal();
|
||||
enumValue = ( (Enum<?>) relationalValue ).ordinal();
|
||||
}
|
||||
final DiscriminatorValueDetails enumMatch = detailsByValue.get( enumValue );
|
||||
if ( enumMatch != null ) {
|
||||
|
@ -107,15 +117,19 @@ public class MixedDiscriminatorConverter<O,R> extends DiscriminatorConverter<O,R
|
|||
}
|
||||
}
|
||||
|
||||
if ( relationalForm instanceof String assumedEntityName ) {
|
||||
// Assume the relational form is the entity name
|
||||
final EntityPersister persister = mappingMetamodel.findEntityDescriptor( assumedEntityName );
|
||||
if ( persister != null ) {
|
||||
return register( assumedEntityName, persister );
|
||||
if ( implicitValueStrategy != null ) {
|
||||
final EntityMappingType entityMapping = implicitValueStrategy.toEntityMapping( relationalValue, discriminatorRole, mappingMetamodel );
|
||||
if ( entityMapping != null ) {
|
||||
return register( relationalValue, entityMapping );
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -125,19 +139,29 @@ public class MixedDiscriminatorConverter<O,R> extends DiscriminatorConverter<O,R
|
|||
return existing;
|
||||
}
|
||||
|
||||
final EntityPersister entityDescriptor = mappingMetamodel.getEntityDescriptor( entityName );
|
||||
return register( entityName, entityDescriptor );
|
||||
if ( implicitValueStrategy != null ) {
|
||||
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
|
||||
public void forEachValueDetail(Consumer<DiscriminatorValueDetails> consumer) {
|
||||
detailsByEntityName.forEach( (value, detail) -> consumer.accept( detail ) );
|
||||
detailsByEntityName.values().forEach( consumer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> X fromValueDetails(Function<DiscriminatorValueDetails, X> handler) {
|
||||
for ( DiscriminatorValueDetails detail : detailsByEntityName.values() ) {
|
||||
final X result = handler.apply( detail );
|
||||
for ( DiscriminatorValueDetails valueDetails : detailsByEntityName.values() ) {
|
||||
final X result = handler.apply( valueDetails );
|
||||
if ( result != null ) {
|
||||
return result;
|
||||
}
|
|
@ -48,7 +48,7 @@ public class AnyMappingDomainTypeImpl<T> implements AnyMappingDomainType<T> {
|
|||
navigableRole,
|
||||
discriminatorBaseType,
|
||||
bootAnyMapping.getMetaValues(),
|
||||
discriminatorType.getValueStrategy(),
|
||||
discriminatorType.getImplicitValueStrategy(),
|
||||
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;
|
||||
|
||||
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 org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.FetchMode;
|
||||
import org.hibernate.Filter;
|
||||
|
@ -101,8 +78,8 @@ import org.hibernate.generator.Generator;
|
|||
import org.hibernate.generator.OnExecutionGenerator;
|
||||
import org.hibernate.generator.internal.VersionGeneration;
|
||||
import org.hibernate.generator.values.GeneratedValues;
|
||||
import org.hibernate.generator.values.internal.GeneratedValuesHelper;
|
||||
import org.hibernate.generator.values.GeneratedValuesMutationDelegate;
|
||||
import org.hibernate.generator.values.internal.GeneratedValuesHelper;
|
||||
import org.hibernate.graph.spi.RootGraphImplementor;
|
||||
import org.hibernate.id.BulkInsertionCapableIdentifierGenerator;
|
||||
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.jdbc.Expectation;
|
||||
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.LoaderSqlAstCreationState;
|
||||
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.DiscriminatorTypeImpl;
|
||||
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.EntityVersionMappingImpl;
|
||||
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.ImmutableAttributeMappingList;
|
||||
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.SimpleAttributeMetadata;
|
||||
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.spi.EntityInstantiator;
|
||||
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.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.emptyMap;
|
||||
|
@ -2278,11 +2277,12 @@ public abstract class AbstractEntityPersister
|
|||
}
|
||||
|
||||
//noinspection rawtypes
|
||||
final DiscriminatorConverter converter = new ExplicitDiscriminatorConverter(
|
||||
final DiscriminatorConverter converter = new UnifiedAnyDiscriminatorConverter<>(
|
||||
getNavigableRole().append( EntityDiscriminatorMapping.DISCRIMINATOR_ROLE_NAME ),
|
||||
domainJavaType,
|
||||
underlingJdbcMapping.getRelationalJavaType(),
|
||||
getSubclassByDiscriminatorValue(),
|
||||
null,
|
||||
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;
|
||||
|
||||
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.FetchMode;
|
||||
import org.hibernate.Hibernate;
|
||||
|
@ -30,8 +22,17 @@ import org.hibernate.persister.entity.Joinable;
|
|||
import org.hibernate.proxy.LazyInitializer;
|
||||
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.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.proxy.HibernateProxy.extractLazyInitializer;
|
||||
|
||||
|
@ -71,7 +72,7 @@ public class AnyType extends AbstractType implements CompositeType, AssociationT
|
|||
return metaType;
|
||||
}
|
||||
|
||||
return new MetaType( discriminatorType, AnyDiscriminatorValueStrategy.AUTO, null );
|
||||
return new MetaType( discriminatorType, FULL_NAME_STRATEGY, null );
|
||||
}
|
||||
|
||||
public Type getIdentifierType() {
|
||||
|
|
|
@ -11,6 +11,7 @@ import org.hibernate.engine.spi.Mapping;
|
|||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.metamodel.spi.ImplicitDiscriminatorStrategy;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
@ -25,47 +26,36 @@ public class MetaType extends AbstractType {
|
|||
public static final String[] REGISTRATION_KEYS = ArrayHelper.EMPTY_STRING_ARRAY;
|
||||
|
||||
private final Type valueType;
|
||||
private final AnyDiscriminatorValueStrategy valueStrategy;
|
||||
private final ImplicitDiscriminatorStrategy implicitValueStrategy;
|
||||
private final Map<Object,String> discriminatorValuesToEntityNameMap;
|
||||
private final Map<String,Object> entityNameToDiscriminatorValueMap;
|
||||
|
||||
public MetaType(
|
||||
Type valueType,
|
||||
AnyDiscriminatorValueStrategy valueStrategy,
|
||||
ImplicitDiscriminatorStrategy implicitValueStrategy,
|
||||
Map<Object,String> explicitValueMappings) {
|
||||
this.valueType = valueType;
|
||||
this.implicitValueStrategy = implicitValueStrategy;
|
||||
|
||||
if ( explicitValueMappings == null || explicitValueMappings.isEmpty() ) {
|
||||
if ( valueStrategy == AnyDiscriminatorValueStrategy.AUTO ) {
|
||||
valueStrategy = AnyDiscriminatorValueStrategy.IMPLICIT;
|
||||
}
|
||||
this.discriminatorValuesToEntityNameMap = new HashMap<>();
|
||||
this.entityNameToDiscriminatorValueMap = new HashMap<>();
|
||||
}
|
||||
else {
|
||||
if ( valueStrategy == AnyDiscriminatorValueStrategy.AUTO ) {
|
||||
valueStrategy = AnyDiscriminatorValueStrategy.EXPLICIT;
|
||||
}
|
||||
this.discriminatorValuesToEntityNameMap = explicitValueMappings;
|
||||
this.entityNameToDiscriminatorValueMap = new HashMap<>();
|
||||
for ( Map.Entry<Object,String> entry : discriminatorValuesToEntityNameMap.entrySet() ) {
|
||||
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() {
|
||||
return valueType;
|
||||
}
|
||||
|
||||
public AnyDiscriminatorValueStrategy getValueStrategy() {
|
||||
return valueStrategy;
|
||||
public ImplicitDiscriminatorStrategy getImplicitValueStrategy() {
|
||||
return implicitValueStrategy;
|
||||
}
|
||||
|
||||
public String[] getRegistrationKeys() {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* 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.Id;
|
||||
|
@ -11,8 +11,12 @@ import jakarta.persistence.Id;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@Entity(name = "CardPayment")
|
||||
//tag::associations-any-example[]
|
||||
@Entity
|
||||
public class CardPayment implements Payment {
|
||||
// ...
|
||||
//end::associations-any-example[]
|
||||
|
||||
@Id
|
||||
private Integer id;
|
||||
private Double amount;
|
||||
|
@ -47,4 +51,6 @@ public class CardPayment implements Payment {
|
|||
public void setAuthorizationCode(String authorizationCode) {
|
||||
this.authorizationCode = authorizationCode;
|
||||
}
|
||||
//tag::associations-any-example[]
|
||||
}
|
||||
//end::associations-any-example[]
|
|
@ -2,7 +2,7 @@
|
|||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* 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.Id;
|
||||
|
@ -11,8 +11,11 @@ import jakarta.persistence.Id;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@Entity(name = "CashPayment")
|
||||
//tag::associations-any-example[]
|
||||
@Entity
|
||||
public class CashPayment implements Payment {
|
||||
// ...
|
||||
//end::associations-any-example[]
|
||||
@Id
|
||||
private Integer id;
|
||||
private Double amount;
|
||||
|
@ -37,4 +40,6 @@ public class CashPayment implements Payment {
|
|||
public void setAmount(Double amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
//tag::associations-any-example[]
|
||||
}
|
||||
//end::associations-any-example[]
|
|
@ -2,7 +2,7 @@
|
|||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* 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.Id;
|
||||
|
@ -11,8 +11,11 @@ import jakarta.persistence.Id;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
//tag::associations-any-example[]
|
||||
@Entity
|
||||
public class CheckPayment implements Payment {
|
||||
// ...
|
||||
//end::associations-any-example[]
|
||||
@Id
|
||||
public Integer id;
|
||||
public Double amount;
|
||||
|
@ -35,4 +38,6 @@ public class CheckPayment implements Payment {
|
|||
public Double getAmount() {
|
||||
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
|
||||
* 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.Id;
|
||||
import jakarta.persistence.Basic;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.Table;
|
||||
import org.hibernate.annotations.Any;
|
||||
import org.hibernate.annotations.AnyDiscriminator;
|
||||
import org.hibernate.annotations.AnyDiscriminatorValue;
|
||||
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
|
||||
|
@ -26,25 +28,15 @@ public class Order {
|
|||
@Basic
|
||||
public String name;
|
||||
|
||||
//tag::associations-any-explicit-discriminator-example[]
|
||||
@Any
|
||||
@AnyKeyJavaClass( Integer.class )
|
||||
@JoinColumn(name = "explicit_fk")
|
||||
@Column( name="explicit_type" )
|
||||
@AnyDiscriminatorValue( discriminator = "CARD", entity = CardPayment.class )
|
||||
@AnyDiscriminatorValue( discriminator = "CHECK", entity = CheckPayment.class )
|
||||
public Payment explicitPayment;
|
||||
|
||||
@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;
|
||||
public Payment paymentExplicit;
|
||||
//end::associations-any-explicit-discriminator-example[]
|
||||
|
||||
protected Order() {
|
||||
// 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