diff --git a/documentation/src/main/asciidoc/userguide/chapters/beans/Beans.adoc b/documentation/src/main/asciidoc/userguide/chapters/beans/Beans.adoc index 32dc655da4..411b86910a 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/beans/Beans.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/beans/Beans.adoc @@ -32,6 +32,8 @@ Hibernate supports using the following integrations as managed beans: * `org.hibernate.type.descriptor.jdbc.JdbcType` * `org.hibernate.type.descriptor.java.BasicJavaType` * `org.hibernate.type.descriptor.java.MutabilityPlan` +* `org.hibernate.usertype.UserType` +* `org.hibernate.usertype.UserCollectionType` * `org.hibernate.metamodel.EmbeddableInstantiator` * `org.hibernate.envers.RevisionListener` * `org.hibernate.id.IdentifierGenerator`{fn-cdi-availability} diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc b/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc index d300e6d033..4f34b60efb 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc @@ -1532,17 +1532,17 @@ See <> for an alternative to `@JavaTypeRegistration` and [[basic-mapping-custom]] ==== Custom type mapping -Another approach is to supply the implementation of the `org.hibernate.usertype.UserType` contract using `@CustomType`. +Another approach is to supply the implementation of the `org.hibernate.usertype.UserType` contract using `@Type`. -There are also corresponding, specialized forms of `@CustomType` for specific model parts: +There are also corresponding, specialized forms of `@Type` for specific model parts: -* When mapping a Map, `@CustomType` describes the Map value while `@MapKeyCustomType` describe the Map key -* When mapping a List or array, `@CustomType` describes the elements while `@ListIndexCustomType` describes the index -* When mapping an id-bag, `@CustomType` describes the elements while `@CollectionIdCustomType` describes the collection-id -* For other collection mappings, `@CustomType` describes the elements -* For discriminated association mappings (`@Any` and `@ManyToAny`), `@CustomType` describes the discriminator value +* When mapping a Map, `@Type` describes the Map value while `@MapKeyCustomType` describe the Map key +* When mapping a List or array, `@Type` describes the elements while `@ListIndexCustomType` describes the index +* When mapping an id-bag, `@Type` describes the elements while `@CollectionIdCustomType` describes the collection-id +* For other collection mappings, `@Type` describes the elements +* For discriminated association mappings (`@Any` and `@ManyToAny`), `@Type` describes the discriminator value -`@UserType` allows for more complex mapping concerns; but, < and +`@Type` allows for more complex mapping concerns; but, < and <> should generally be preferred as simpler solutions [[basic-nationalized]] diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/collections.adoc b/documentation/src/main/asciidoc/userguide/chapters/domain/collections.adoc index 254ecbf34c..972565f7b6 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/collections.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/collections.adoc @@ -237,7 +237,7 @@ Some apps map BAG collections using `java.util.List` instead. Hibernate provide lists as bags. First an explicit annotation [[collection-bag-list-ex]] -.List as BAG +.@Bag ==== [source, JAVA, indent=0] ---- @@ -245,11 +245,11 @@ include::{classificationTestsDir}/bag/EntityWithBagAsList.java[tags=collections- ---- ==== -Specifically, the usage of `@CollectionClassificationType(BAG)` forces the interpretation to -BAG. See <> for details on using `@CollectionClassificationType`. +Specifically, the usage of `@Bag` forces the classification as BAG. Even though the `names` attribute is defined +as `List`, Hibernate will treat it using the BAG semantics. Additionally, as discussed in <>, the `hibernate.mapping.default_list_semantics` setting -is available to have Hibernate interpret a `List` with no `@OrderColumn` as a BAG. +is available to have Hibernate interpret a `List` with no `@OrderColumn` and no `@ListIndexBase` as a BAG. An ID_BAG is similar to a BAG, except that it maps a generated, per-row identifier into the collection @@ -380,118 +380,16 @@ Id:: the identifier for an ID_BAG // todo (6.0) - finish -[[collection-semantics-influence]] -==== Influencing CollectionSemantics - -Hibernate provides multiple ways to influence the `CollectionSemantics used to -map any particular plural attribute: - -1. <> -2. <> -3. <> - - - -[[collection-classification-ann]] -===== @CollectionClassificationType - -`@CollectionClassificationType` allows directly telling Hibernate which semantics to use -through its classification. - -For example, as discussed in <>, Hibernate will map a `java.util.Collection` -using BAG semantics by default. - -As seen in <>, we can use the `@CollectionClassificationType` -annotation to request it handled using a different semantic - there LIST. - -In fact, we can use this technique with any of the classifications as long -as the attribute's declared type on the domain model is assignable from the type -implied by the semantic associated with the classification. The most common case where -this would be useful is when exposing a plural attribute using `java.util.Collection` but -telling Hibernate to use a semantic other than BAG. E.g., to use SET semantics for a -`java.util.Collection` - - -[[collection-bag-set-ex]] -.Collection as SET -==== -[source, JAVA, indent=0] ----- -include::{classificationTestsDir}/explicit/EntityWithExplicitSetClassification.java[tags=collections-bag-set-ex] ----- -==== - - -[[collection-semantics-ann]] -===== @CollectionSemantics - -Applications can also use the `@CollectionSemantics` annotation to specify a custom -link:{javadoc-base}/org/hibernate/collection/spi/CollectionSemantics.html[`org.hibernate.collection.spi.CollectionSemantics`] -implementation to use for the plural attribute. - -As an example, consider a requirement for a collection with the semantics of a "unique list" - a -cross between the ordered-ness of a `List` and the uniqueness of a `Set`. First the entity: - - -[[collection-semantics-ann-ex]] -.@CollectionSemantics -==== -[source, JAVA, indent=0] ----- -include::{coreCollectionTestsDir}/semantics/TheEntityWithUniqueList.java[tags=collections-custom-semantics-ex] ----- -==== - -The mapping specifies that a custom `UniqueListSemantic` should be used as the `CollectionSemantics` for the -`strings` attribute. - - -[[collection-semantics-ann-impl-ex]] -.@CollectionSemantics -==== -[source, JAVA, indent=0] ----- -include::{coreCollectionTestsDir}/semantics/UniqueListSemantic.java[tags=collections-custom-semantics-ex] ----- -==== - -`UniqueListSemantic` defines the actual semantics of what a unique list is and how Hibernate should handle it. - -See the `CollectionSemantics` link:{javadoc-base}/org/hibernate/collection/spi/CollectionSemantics.html[javadoc] for -details. - - -[[collection-semantics-ann-wrapper-ex]] -.PersistentCollection -==== -[source, JAVA, indent=0] ----- -include::{coreCollectionTestsDir}/semantics/UniqueListWrapper.java[tags=collections-custom-semantics-ex] ----- -==== - -Most custom `CollectionSemantics` will need their own `PersistentCollection` implementation. -`UniqueListWrapper` is the `PersistentCollection` implementation for the "unique list" semantic. -See <> for more details. - - -For cases where an application wants to apply the same custom semantic to all -plural attributes of a given classification, Hibernate also provides the -`@CollectionSemanticsRegistration`: - -// todo (6.0) - example of using `@CollectionSemanticsRegistration` - [[collection-type-ann]] -===== @CollectionType +==== @CollectionType The `@CollectionType` annotation provides the ability to use a custom link:{javadoc-base}/org/hibernate/usertype/UserCollectionType.html[`UserCollectionType`] -implementation. +implementation to influence how the collection for a plural attribute behaves. -Let's revisit the requirement of needing a unique list that was used -in <> and see how to implement the same behavior using -`UserCollectionType`. +As an example, consider a requirement for a collection with the semantics of a "unique list" - a +cross between the ordered-ness of a `List` and the uniqueness of a `Set`. First the entity: [[collection-type-ann-ex]] @@ -499,7 +397,7 @@ in <> and see how to implement the same behavior using ==== [source, JAVA, indent=0] ---- -include::{coreCollectionTestsDir}/semantics/AnotherEntityWithUniqueList.java[tags=collections-custom-type-ex] +include::{coreCollectionTestsDir}/semantics/TheEntityWithUniqueList.java[tags=ex-collections-custom-type-model] ---- ==== @@ -514,6 +412,30 @@ include::{coreCollectionTestsDir}/semantics/UniqueListType.java[tags=collections ---- ==== +Most custom `UserCollectionType` implementations will want their own `PersistentCollection` implementation. + +[[collection-type-usertype-wrapper-ex]] +.UniqueListWrapper +==== +[source, JAVA, indent=0] +---- +include::{coreCollectionTestsDir}/semantics/UniqueListWrapper.java[tags=collections-custom-semantics-ex] +---- +==== + +`UniqueListWrapper` is the `PersistentCollection` implementation for the "unique list" semantic. See <> for more details. + + +For cases where an application wants to apply the same custom type to all +plural attributes of a given classification, Hibernate also provides the +`@CollectionTypeRegistration`: + +// todo (6.0) - example of using `@CollectionTypeRegistration` + + +[[collection-type-reg-ann]] +==== @CollectionTypeRegistration + [[collection-wrapper]] diff --git a/documentation/src/test/java/org/hibernate/userguide/collections/type/QueueType.java b/documentation/src/test/java/org/hibernate/userguide/collections/type/QueueType.java index 42c24b0745..eede978b70 100644 --- a/documentation/src/test/java/org/hibernate/userguide/collections/type/QueueType.java +++ b/documentation/src/test/java/org/hibernate/userguide/collections/type/QueueType.java @@ -15,11 +15,21 @@ import java.util.Queue; import org.hibernate.HibernateException; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.metamodel.CollectionClassification; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.usertype.UserCollectionType; //tag::collections-custom-collection-mapping-example[] public class QueueType implements UserCollectionType { + @Override + public CollectionClassification getClassification() { + return CollectionClassification.BAG; + } + + @Override + public Class getCollectionClass() { + return Queue.class; + } @Override public PersistentCollection instantiate( diff --git a/documentation/src/test/java/org/hibernate/userguide/mapping/basic/EnumerationCustomTypeTest.java b/documentation/src/test/java/org/hibernate/userguide/mapping/basic/EnumerationCustomTypeTest.java index 884f314855..04b7e5b950 100644 --- a/documentation/src/test/java/org/hibernate/userguide/mapping/basic/EnumerationCustomTypeTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/mapping/basic/EnumerationCustomTypeTest.java @@ -6,7 +6,7 @@ */ package org.hibernate.userguide.mapping.basic; -import org.hibernate.annotations.CustomType; +import org.hibernate.annotations.Type; import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; import org.junit.Test; @@ -48,7 +48,7 @@ public class EnumerationCustomTypeTest extends BaseEntityManagerFunctionalTestCa private String name; - @CustomType(org.hibernate.userguide.mapping.basic.GenderType.class) + @Type(org.hibernate.userguide.mapping.basic.GenderType.class) public Gender gender; //Getters and setters are omitted for brevity diff --git a/documentation/src/test/java/org/hibernate/userguide/mapping/basic/ExplicitTypeTest.java b/documentation/src/test/java/org/hibernate/userguide/mapping/basic/ExplicitTypeTest.java index 760d211106..7edf9b98a5 100644 --- a/documentation/src/test/java/org/hibernate/userguide/mapping/basic/ExplicitTypeTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/mapping/basic/ExplicitTypeTest.java @@ -9,7 +9,7 @@ package org.hibernate.userguide.mapping.basic; import jakarta.persistence.Entity; import jakarta.persistence.Id; -import org.hibernate.annotations.CustomType; +import org.hibernate.annotations.Type; import org.hibernate.annotations.Parameter; import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; import org.hibernate.usertype.UserTypeLegacyBridge; @@ -46,13 +46,13 @@ public class ExplicitTypeTest extends BaseEntityManagerFunctionalTestCase { private String sku; - @CustomType( + @Type( value = UserTypeLegacyBridge.class, parameters = @Parameter(name = UserTypeLegacyBridge.TYPE_NAME_PARAM_KEY, value = "nstring") ) private String name; - @CustomType( + @Type( value = UserTypeLegacyBridge.class, parameters = @Parameter(name = UserTypeLegacyBridge.TYPE_NAME_PARAM_KEY, value = "materialized_nclob") ) diff --git a/documentation/src/test/java/org/hibernate/userguide/mapping/basic/bitset/BitSetUserTypeTest.java b/documentation/src/test/java/org/hibernate/userguide/mapping/basic/bitset/BitSetUserTypeTest.java index ed8692c300..10b02b673d 100644 --- a/documentation/src/test/java/org/hibernate/userguide/mapping/basic/bitset/BitSetUserTypeTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/mapping/basic/bitset/BitSetUserTypeTest.java @@ -8,7 +8,7 @@ package org.hibernate.userguide.mapping.basic.bitset; import java.util.BitSet; -import org.hibernate.annotations.CustomType; +import org.hibernate.annotations.Type; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.Test; @@ -107,7 +107,7 @@ public class BitSetUserTypeTest extends BaseCoreFunctionalTestCase { @Id private Integer id; - @CustomType(BitSetUserType.class) + @Type(BitSetUserType.class) @Column(name = "bitset_col") private BitSet bitSet; diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/CollectionSemantics.java b/hibernate-core/src/main/java/org/hibernate/annotations/Bag.java similarity index 70% rename from hibernate-core/src/main/java/org/hibernate/annotations/CollectionSemantics.java rename to hibernate-core/src/main/java/org/hibernate/annotations/Bag.java index 96b89051f3..0878c83dc9 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/CollectionSemantics.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/Bag.java @@ -14,14 +14,15 @@ import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** - * Specifies a custom {@link org.hibernate.collection.spi.CollectionSemantics} + * Can be used to map a {@link java.util.List}-valued attribute using + * {@link org.hibernate.metamodel.CollectionClassification#BAG} semantics. * - * @since 6.0 + * @apiNote Ignored if either {@link jakarta.persistence.OrderColumn} or + * {@link ListIndexBase} is used. * * @author Steve Ebersole */ @java.lang.annotation.Target({METHOD, FIELD, ANNOTATION_TYPE}) @Retention(RUNTIME) -public @interface CollectionSemantics { - Class value(); +public @interface Bag { } diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/CollectionClassificationType.java b/hibernate-core/src/main/java/org/hibernate/annotations/CollectionClassificationType.java deleted file mode 100644 index 94ce4a8bb3..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/annotations/CollectionClassificationType.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ -package org.hibernate.annotations; - -import java.lang.annotation.Retention; - -import org.hibernate.metamodel.CollectionClassification; - -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; - -/** - * @since 6.0 - * - * @author Steve Ebersole - */ -@java.lang.annotation.Target({METHOD, FIELD, ANNOTATION_TYPE}) -@Retention(RUNTIME) -public @interface CollectionClassificationType { - CollectionClassification value(); -} diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/CollectionIdCustomType.java b/hibernate-core/src/main/java/org/hibernate/annotations/CollectionIdCustomType.java index 0d1f46ef36..482226df46 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/CollectionIdCustomType.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/CollectionIdCustomType.java @@ -15,7 +15,7 @@ import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** - * Form of {@link CustomType} for describing the id of an id-bag mapping + * Form of {@link Type} for describing the id of an id-bag mapping * * @since 6.0 */ @@ -26,7 +26,7 @@ public @interface CollectionIdCustomType { /** * The custom type implementor class * - * @see CustomType#value + * @see Type#value */ Class> value(); @@ -37,7 +37,7 @@ public @interface CollectionIdCustomType { * The type should implement {@link org.hibernate.usertype.ParameterizedType} * to receive the parameters * - * @see CustomType#parameters + * @see Type#parameters */ Parameter[] parameters() default {}; } diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/CollectionSemanticsRegistration.java b/hibernate-core/src/main/java/org/hibernate/annotations/CollectionSemanticsRegistration.java deleted file mode 100644 index c801728e66..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/annotations/CollectionSemanticsRegistration.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ -package org.hibernate.annotations; - -import java.lang.annotation.Repeatable; -import java.lang.annotation.Retention; - -import org.hibernate.metamodel.CollectionClassification; - -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; - -/** - * Allows to register a {@link org.hibernate.collection.spi.CollectionSemantics} - * to use as the default for the specified classification of collection. - * - * @see CollectionClassificationType - * @see CollectionSemantics - * @see org.hibernate.collection.spi.CollectionSemantics - * - * @since 6.0 - * - * @author Steve Ebersole - */ -@java.lang.annotation.Target({METHOD, FIELD, ANNOTATION_TYPE}) -@Retention(RUNTIME) -@Repeatable( CollectionSemanticsRegistrations.class ) -public @interface CollectionSemanticsRegistration { - /** - * The collection classification for which the supplied semantic applies - */ - CollectionClassification classification(); - - /** - * The semantic to apply. Will be applied to all collections of the given - * classification which do not define an explicit {@link org.hibernate.collection.spi.CollectionSemantics} - */ - Class> semantics(); -} diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/CollectionType.java b/hibernate-core/src/main/java/org/hibernate/annotations/CollectionType.java index 774650d851..5f7d99648d 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/CollectionType.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/CollectionType.java @@ -29,18 +29,6 @@ public @interface CollectionType { */ Class type(); - /** - * Specifies the class to use the semantics of. - * - * For example, specifying {@link java.util.Set} will use Set semantics. - * - * When not specified, will be inferred from the interfaces on the property - * as long as it extends a standard {@link java.util.Collection} or {@link java.util.Map}. - * - * @return the class to use the semantics of. - */ - Class semantics() default void.class; - /** * Specifies configuration information for the type. Note that if the named type is a * {@link org.hibernate.usertype.UserCollectionType}, it must also implement diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/CollectionTypeRegistration.java b/hibernate-core/src/main/java/org/hibernate/annotations/CollectionTypeRegistration.java new file mode 100644 index 0000000000..2fd448dfda --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/annotations/CollectionTypeRegistration.java @@ -0,0 +1,53 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.annotations; + +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; + +import org.hibernate.metamodel.CollectionClassification; +import org.hibernate.usertype.UserCollectionType; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PACKAGE; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Allows to register a {@link org.hibernate.usertype.UserCollectionType} + * to use as the default for the specified classification of collection. + * + * @see CollectionType + * + * @since 6.0 + * + * @author Steve Ebersole + */ +@java.lang.annotation.Target({TYPE, PACKAGE, ANNOTATION_TYPE}) +@Retention(RUNTIME) +@Repeatable( CollectionTypeRegistrations.class ) +public @interface CollectionTypeRegistration { + /** + * The collection classification for which the supplied type applies + */ + CollectionClassification classification(); + + /** + * Specifies the UserCollectionType to use when we encounter + * a plural attribute classified as {@link #classification()} + */ + Class type(); + + /** + * Specifies configuration information for the type. Note that if the named type is a + * {@link org.hibernate.usertype.UserCollectionType}, it must also implement + * {@link org.hibernate.usertype.ParameterizedType} in order to receive these values. + */ + Parameter[] parameters() default {}; +} diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/CollectionSemanticsRegistrations.java b/hibernate-core/src/main/java/org/hibernate/annotations/CollectionTypeRegistrations.java similarity index 67% rename from hibernate-core/src/main/java/org/hibernate/annotations/CollectionSemanticsRegistrations.java rename to hibernate-core/src/main/java/org/hibernate/annotations/CollectionTypeRegistrations.java index fb9f913412..19504d41e4 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/CollectionSemanticsRegistrations.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/CollectionTypeRegistrations.java @@ -11,20 +11,21 @@ import java.lang.annotation.Retention; import static java.lang.annotation.ElementType.ANNOTATION_TYPE; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** - * Repeatable container for {@link CollectionSemanticsRegistration} + * Repeatable container for {@link CollectionTypeRegistration} * * @since 6.0 * * @author Steve Ebersole */ -@java.lang.annotation.Target({METHOD, FIELD, ANNOTATION_TYPE}) +@java.lang.annotation.Target({TYPE, ANNOTATION_TYPE}) @Retention(RUNTIME) -public @interface CollectionSemanticsRegistrations { +public @interface CollectionTypeRegistrations { /** - * The individual CollectionSemanticsRegistrations + * The individual CollectionTypeRegistration */ - CollectionSemanticsRegistration[] value(); + CollectionTypeRegistration[] value(); } diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/MapKeyCustomType.java b/hibernate-core/src/main/java/org/hibernate/annotations/MapKeyCustomType.java index dfbed8d371..f9bc20b678 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/MapKeyCustomType.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/MapKeyCustomType.java @@ -9,7 +9,7 @@ package org.hibernate.annotations; import org.hibernate.usertype.UserType; /** - * Form of {@link CustomType} for use with map-keys + * Form of {@link Type} for use with map-keys * * @since 6.0 */ @@ -17,14 +17,14 @@ public @interface MapKeyCustomType { /** * The custom type implementor class * - * @see CustomType#value + * @see Type#value */ Class> value(); /** * Parameters for the custom type * - * @see CustomType#parameters + * @see Type#parameters */ Parameter[] parameters() default {}; } diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/CustomType.java b/hibernate-core/src/main/java/org/hibernate/annotations/Type.java similarity index 97% rename from hibernate-core/src/main/java/org/hibernate/annotations/CustomType.java rename to hibernate-core/src/main/java/org/hibernate/annotations/Type.java index 4ace6ed9f3..f13dae636c 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/CustomType.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/Type.java @@ -22,7 +22,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; */ @java.lang.annotation.Target({METHOD, FIELD}) @Retention(RUNTIME) -public @interface CustomType { +public @interface Type { /** * The custom type implementor class diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/package-info.java b/hibernate-core/src/main/java/org/hibernate/annotations/package-info.java index 81e06ff7fa..06cc588aea 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/package-info.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/package-info.java @@ -31,7 +31,7 @@ * *
  • * Contracted via the {@link org.hibernate.usertype.UserType} interface and specified using - * {@link org.hibernate.annotations.CustomType}. + * {@link org.hibernate.annotations.Type}. * As with the compositional approach, there are model-part specific annotations for specifying * custom-types as well. *
  • diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java index e6b9c7a54e..eb61fd6457 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java @@ -15,6 +15,7 @@ import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Properties; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -27,6 +28,8 @@ import org.hibernate.DuplicateMappingException; import org.hibernate.HibernateException; import org.hibernate.MappingException; import org.hibernate.SessionFactory; +import org.hibernate.annotations.CollectionTypeRegistration; +import org.hibernate.annotations.Parameter; import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.boot.CacheRegionDefinition; import org.hibernate.boot.SessionFactoryBuilder; @@ -54,6 +57,7 @@ import org.hibernate.boot.query.NamedProcedureCallDefinition; import org.hibernate.boot.query.NamedResultSetMappingDescriptor; import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.boot.spi.InFlightMetadataCollector; +import org.hibernate.boot.spi.InFlightMetadataCollector.CollectionTypeRegistrationDescriptor; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.MetadataBuildingOptions; import org.hibernate.boot.spi.NaturalIdUniqueKeyBinder; @@ -95,12 +99,14 @@ import org.hibernate.mapping.RootClass; import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.Table; import org.hibernate.mapping.UniqueKey; +import org.hibernate.metamodel.CollectionClassification; import org.hibernate.metamodel.EmbeddableInstantiator; import org.hibernate.query.named.NamedObjectRepository; import org.hibernate.query.sqm.function.SqmFunctionDescriptor; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.spi.TypeConfiguration; +import org.hibernate.usertype.UserCollectionType; import jakarta.persistence.AttributeConverter; import jakarta.persistence.Embeddable; @@ -407,6 +413,48 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector return registeredInstantiators.get( embeddableType ); } + private Map collectionTypeRegistrations; + + + @Override + public void addCollectionTypeRegistration(CollectionTypeRegistration registrationAnnotation) { + addCollectionTypeRegistration( + registrationAnnotation.classification(), + toDescriptor( registrationAnnotation ) + ); + } + + @Override + public void addCollectionTypeRegistration(CollectionClassification classification, CollectionTypeRegistrationDescriptor descriptor) { + if ( collectionTypeRegistrations == null ) { + collectionTypeRegistrations = new HashMap<>(); + } + collectionTypeRegistrations.put( classification, descriptor ); + } + + @Override + public CollectionTypeRegistrationDescriptor findCollectionTypeRegistration(CollectionClassification classification) { + if ( collectionTypeRegistrations == null ) { + return null; + } + + return collectionTypeRegistrations.get( classification ); + } + + private CollectionTypeRegistrationDescriptor toDescriptor(CollectionTypeRegistration registrationAnnotation) { + final Properties parameters; + if ( registrationAnnotation.parameters().length > 0 ) { + parameters = new Properties(); + for ( Parameter parameter : registrationAnnotation.parameters() ) { + parameters.put( parameter.name(), parameter.value() ); + } + } + else { + parameters = null; + } + return new CollectionTypeRegistrationDescriptor( registrationAnnotation.type(), parameters ); + } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // attribute converters diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/InFlightMetadataCollector.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/InFlightMetadataCollector.java index fb98fd5f99..9ddabaaad9 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/InFlightMetadataCollector.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/InFlightMetadataCollector.java @@ -10,11 +10,13 @@ import java.io.Serializable; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Properties; import java.util.function.Function; import org.hibernate.DuplicateMappingException; import org.hibernate.HibernateException; import org.hibernate.MappingException; +import org.hibernate.annotations.CollectionTypeRegistration; import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.boot.internal.ClassmateContext; import org.hibernate.boot.internal.NamedProcedureCallDefinitionImpl; @@ -49,9 +51,11 @@ import org.hibernate.mapping.Join; import org.hibernate.mapping.MappedSuperclass; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Table; +import org.hibernate.metamodel.CollectionClassification; import org.hibernate.metamodel.EmbeddableInstantiator; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.jdbc.JdbcType; +import org.hibernate.usertype.UserCollectionType; import jakarta.persistence.AttributeConverter; @@ -323,6 +327,10 @@ public interface InFlightMetadataCollector extends Mapping, MetadataImplementor void registerEmbeddableInstantiator(Class embeddableType, Class instantiator); Class findRegisteredEmbeddableInstantiator(Class embeddableType); + void addCollectionTypeRegistration(CollectionTypeRegistration registrationAnnotation); + void addCollectionTypeRegistration(CollectionClassification classification, CollectionTypeRegistrationDescriptor descriptor); + CollectionTypeRegistrationDescriptor findCollectionTypeRegistration(CollectionClassification classification); + interface DelayedPropertyReferenceHandler extends Serializable { void process(InFlightMetadataCollector metadataCollector); } @@ -371,4 +379,23 @@ public interface InFlightMetadataCollector extends Mapping, MetadataImplementor Table primaryTable, EntityTableXref superEntityTableXref); Map getJoins(String entityName); + + + class CollectionTypeRegistrationDescriptor { + private final Class implementation; + private final Properties parameters; + + public CollectionTypeRegistrationDescriptor(Class implementation, Properties parameters) { + this.implementation = implementation; + this.parameters = parameters; + } + + public Class getImplementation() { + return implementation; + } + + public Properties getParameters() { + return parameters; + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java index 25cbef2683..4650ec3572 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java @@ -19,7 +19,6 @@ import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Properties; import java.util.Set; import org.hibernate.AnnotationException; @@ -33,6 +32,8 @@ import org.hibernate.annotations.Cascade; import org.hibernate.annotations.CascadeType; import org.hibernate.annotations.Check; import org.hibernate.annotations.CollectionId; +import org.hibernate.annotations.CollectionTypeRegistration; +import org.hibernate.annotations.CollectionTypeRegistrations; import org.hibernate.annotations.Columns; import org.hibernate.annotations.Comment; import org.hibernate.annotations.DiscriminatorFormula; @@ -873,16 +874,18 @@ public final class AnnotationBinder { } } } - } - private static Properties extractProperties(Parameter[] parameters) { - final Properties properties = new Properties(); - if ( parameters.length > 0 ) { - for ( int i = 0; i < parameters.length; i++ ) { - properties.setProperty( parameters[i].name(), parameters[i].value() ); + final CollectionTypeRegistration singleRegistration = annotatedElement.getAnnotation( CollectionTypeRegistration.class ); + if ( singleRegistration != null ) { + context.getMetadataCollector().addCollectionTypeRegistration( singleRegistration ); + } + + final CollectionTypeRegistrations multiRegistration = annotatedElement.getAnnotation( CollectionTypeRegistrations.class ); + if ( multiRegistration != null ) { + for ( CollectionTypeRegistration registration : multiRegistration.value() ) { + context.getMetadataCollector().addCollectionTypeRegistration( registration ); } } - return properties; } private static void handleSqlTypeDescriptorRegistration( diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/PropertyContainer.java b/hibernate-core/src/main/java/org/hibernate/cfg/PropertyContainer.java index 1fe0b8b0f5..1ee2caa13f 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/PropertyContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/PropertyContainer.java @@ -19,7 +19,7 @@ import java.util.Map; import java.util.TreeMap; import org.hibernate.AnnotationException; -import org.hibernate.annotations.CustomType; +import org.hibernate.annotations.Type; import org.hibernate.annotations.JavaType; import org.hibernate.annotations.ManyToAny; import org.hibernate.annotations.Target; @@ -385,7 +385,7 @@ class PropertyContainer { else if ( p.isAnnotationPresent( Basic.class ) ) { return true; } - else if ( p.isAnnotationPresent( CustomType.class ) ) { + else if ( p.isAnnotationPresent( Type.class ) ) { return true; } else if ( p.isAnnotationPresent( JavaType.class ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/ArrayBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/ArrayBinder.java index d06d10ec1a..27a146e8db 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/ArrayBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/ArrayBinder.java @@ -6,11 +6,15 @@ */ package org.hibernate.cfg.annotations; +import java.util.function.Supplier; + import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.mapping.Array; import org.hibernate.mapping.Collection; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.SemanticsResolver; +import org.hibernate.resource.beans.spi.ManagedBean; +import org.hibernate.usertype.UserCollectionType; /** * Bind an Array @@ -18,11 +22,11 @@ import org.hibernate.mapping.SemanticsResolver; * @author Anthony Patricio */ public class ArrayBinder extends ListBinder { - public ArrayBinder(SemanticsResolver semanticsResolver, MetadataBuildingContext buildingContext) { - super( semanticsResolver, buildingContext ); + public ArrayBinder(Supplier> customTypeBeanResolver, MetadataBuildingContext buildingContext) { + super( customTypeBeanResolver, buildingContext ); } protected Collection createCollection(PersistentClass owner) { - return new Array( getSemanticsResolver(), owner, getBuildingContext() ); + return new Array( getCustomTypeBeanResolver(), owner, getBuildingContext() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/BagBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/BagBinder.java index cc6e525d9d..52f6c1d2fc 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/BagBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/BagBinder.java @@ -6,10 +6,14 @@ */ package org.hibernate.cfg.annotations; +import java.util.function.Supplier; + import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.mapping.Collection; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.SemanticsResolver; +import org.hibernate.resource.beans.spi.ManagedBean; +import org.hibernate.usertype.UserCollectionType; /** * Bind a bag. @@ -17,11 +21,11 @@ import org.hibernate.mapping.SemanticsResolver; * @author Matthew Inger */ public class BagBinder extends CollectionBinder { - public BagBinder(SemanticsResolver semanticsResolver, MetadataBuildingContext context) { - super( semanticsResolver, false, context ); + public BagBinder(Supplier> customTypeBeanResolver, MetadataBuildingContext context) { + super( customTypeBeanResolver, false, context ); } protected Collection createCollection(PersistentClass owner) { - return new org.hibernate.mapping.Bag( getSemanticsResolver(), owner, getBuildingContext() ); + return new org.hibernate.mapping.Bag( getCustomTypeBeanResolver(), owner, getBuildingContext() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/BasicValueBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/BasicValueBinder.java index 32d6f5928e..1f48fe9829 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/BasicValueBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/BasicValueBinder.java @@ -31,7 +31,7 @@ import org.hibernate.annotations.CollectionIdJavaType; import org.hibernate.annotations.CollectionIdJdbcType; import org.hibernate.annotations.CollectionIdJdbcTypeCode; import org.hibernate.annotations.CollectionIdMutability; -import org.hibernate.annotations.CustomType; +import org.hibernate.annotations.Type; import org.hibernate.annotations.Immutable; import org.hibernate.annotations.JdbcTypeCode; import org.hibernate.annotations.ListIndexJavaType; @@ -1434,7 +1434,7 @@ public class BasicValueBinder implements JdbcTypeDescriptorIndicators { @Override public Class> customType(XProperty xProperty) { - final CustomType customType = findAnnotation( xProperty, CustomType.class ); + final Type customType = findAnnotation( xProperty, Type.class ); if ( customType == null ) { return null; } @@ -1444,7 +1444,7 @@ public class BasicValueBinder implements JdbcTypeDescriptorIndicators { @Override public Parameter[] customTypeParameters(XProperty xProperty) { - final CustomType customType = findAnnotation( xProperty, CustomType.class ); + final Type customType = findAnnotation( xProperty, Type.class ); if ( customType == null ) { return null; } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/CollectionBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/CollectionBinder.java index a49fda954a..446c6bc42c 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/CollectionBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/CollectionBinder.java @@ -13,19 +13,19 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; +import java.util.function.Supplier; import org.hibernate.AnnotationException; import org.hibernate.AssertionFailure; import org.hibernate.FetchMode; import org.hibernate.MappingException; +import org.hibernate.annotations.Bag; import org.hibernate.annotations.BatchSize; import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CollectionClassificationType; import org.hibernate.annotations.CollectionId; import org.hibernate.annotations.CollectionIdJavaType; import org.hibernate.annotations.CollectionIdJdbcType; import org.hibernate.annotations.CollectionIdJdbcTypeCode; -import org.hibernate.annotations.CollectionSemantics; import org.hibernate.annotations.CollectionType; import org.hibernate.annotations.Fetch; import org.hibernate.annotations.Filter; @@ -60,19 +60,22 @@ import org.hibernate.annotations.Where; import org.hibernate.annotations.WhereJoinTable; import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.annotations.common.reflection.XProperty; +import org.hibernate.boot.BootLogging; import org.hibernate.boot.model.IdentifierGeneratorDefinition; import org.hibernate.boot.model.TypeDefinition; +import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.spi.InFlightMetadataCollector; +import org.hibernate.boot.spi.InFlightMetadataCollector.CollectionTypeRegistrationDescriptor; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.cfg.AccessType; import org.hibernate.cfg.AnnotatedClassType; +import org.hibernate.cfg.AnnotatedColumn; +import org.hibernate.cfg.AnnotatedJoinColumn; import org.hibernate.cfg.AnnotationBinder; import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.BinderHelper; import org.hibernate.cfg.CollectionPropertyHolder; import org.hibernate.cfg.CollectionSecondPass; -import org.hibernate.cfg.AnnotatedColumn; -import org.hibernate.cfg.AnnotatedJoinColumn; import org.hibernate.cfg.IndexColumn; import org.hibernate.cfg.InheritanceState; import org.hibernate.cfg.PropertyData; @@ -81,11 +84,11 @@ import org.hibernate.cfg.PropertyHolderBuilder; import org.hibernate.cfg.PropertyInferredData; import org.hibernate.cfg.PropertyPreloadedData; import org.hibernate.cfg.SecondPass; -import org.hibernate.collection.internal.CustomCollectionTypeSemantics; import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.StringHelper; +import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.mapping.Any; import org.hibernate.mapping.Backref; @@ -99,13 +102,14 @@ import org.hibernate.mapping.ManyToOne; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; import org.hibernate.mapping.Selectable; -import org.hibernate.mapping.SemanticsResolver; import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.Table; import org.hibernate.metamodel.CollectionClassification; import org.hibernate.metamodel.EmbeddableInstantiator; import org.hibernate.resource.beans.spi.ManagedBean; import org.hibernate.resource.beans.spi.ManagedBeanRegistry; +import org.hibernate.usertype.ParameterizedType; +import org.hibernate.usertype.UserCollectionType; import org.jboss.logging.Logger; @@ -150,7 +154,7 @@ public abstract class CollectionBinder { ); private final MetadataBuildingContext buildingContext; - private final SemanticsResolver semanticsResolver; + private final Supplier> customTypeBeanResolver; private final boolean isSortedCollection; protected Collection collection; @@ -194,8 +198,11 @@ public abstract class CollectionBinder { private String explicitType; private final Properties explicitTypeParameters = new Properties(); - protected CollectionBinder(SemanticsResolver semanticsResolver, boolean isSortedCollection, MetadataBuildingContext buildingContext) { - this.semanticsResolver = semanticsResolver; + protected CollectionBinder( + Supplier> customTypeBeanResolver, + boolean isSortedCollection, + MetadataBuildingContext buildingContext) { + this.customTypeBeanResolver = customTypeBeanResolver; this.isSortedCollection = isSortedCollection; this.buildingContext = buildingContext; } @@ -204,8 +211,8 @@ public abstract class CollectionBinder { return buildingContext; } - protected SemanticsResolver getSemanticsResolver() { - return semanticsResolver; + public Supplier> getCustomTypeBeanResolver() { + return customTypeBeanResolver; } public boolean isMap() { @@ -286,15 +293,20 @@ public abstract class CollectionBinder { final CollectionBinder binder; if ( typeAnnotation != null ) { binder = createBinderFromCustomTypeAnnotation( property, typeAnnotation, buildingContext ); + + // todo (6.0) - technically, these should no longer be needed binder.explicitType = typeAnnotation.type().getName(); for ( Parameter param : typeAnnotation.parameters() ) { binder.explicitTypeParameters.setProperty( param.name(), param.value() ); } } else { - final CollectionSemantics customSemantics = property.getAnnotation( CollectionSemantics.class ); - if ( customSemantics != null ) { - binder = createBinderFromCustomSemantics( customSemantics, property, buildingContext ); + final CollectionClassification classification = determineCollectionClassification( property, buildingContext ); + final CollectionTypeRegistrationDescriptor typeRegistration = buildingContext + .getMetadataCollector() + .findCollectionTypeRegistration( classification ); + if ( typeRegistration != null ) { + binder = createBinderFromTypeRegistration( property, classification, typeRegistration, buildingContext ); } else { binder = createBinderFromProperty( property, buildingContext ); @@ -306,74 +318,164 @@ public abstract class CollectionBinder { return binder; } - private static CollectionBinder createBinderFromCustomSemantics( - CollectionSemantics customSemantics, + private static CollectionBinder createBinderFromTypeRegistration( XProperty property, + CollectionClassification classification, + CollectionTypeRegistrationDescriptor typeRegistration, MetadataBuildingContext buildingContext) { - final ManagedBeanRegistry beanRegistry = buildingContext.getBootstrapContext() - .getServiceRegistry() - .getService( ManagedBeanRegistry.class ); - final ManagedBean semanticsBean = beanRegistry.getBean( customSemantics.value() ); - final org.hibernate.collection.spi.CollectionSemantics semantics = semanticsBean.getBeanInstance(); return createBinder( property, - semantics.getCollectionClassification(), - (type) -> semantics, + () -> createCustomType( + property.getDeclaringClass().getName() + "#" + property.getName(), + typeRegistration.getImplementation(), + typeRegistration.getParameters(), + buildingContext + ), + classification, buildingContext ); } + private static ManagedBean createCustomType( + String role, + Class implementation, + Properties parameters, + MetadataBuildingContext buildingContext) { + final StandardServiceRegistry serviceRegistry = buildingContext.getBuildingOptions().getServiceRegistry(); + final ManagedBeanRegistry beanRegistry = serviceRegistry.getService( ManagedBeanRegistry.class ); + if ( CollectionHelper.isNotEmpty( parameters ) ) { + return beanRegistry.getBean( implementation ); + } + else { + // defined parameters... + if ( ParameterizedType.class.isAssignableFrom( implementation ) ) { + // because there are config parameters and the type is configurable, we need + // a separate bean instance which means uniquely naming it + final ManagedBean typeBean = beanRegistry.getBean( role, implementation ); + final UserCollectionType type = typeBean.getBeanInstance(); + ( (ParameterizedType) type ).setParameterValues( parameters ); + return typeBean; + } + else { + // log a "warning" + BootLogging.LOGGER.debugf( + "Custom collection-type (`%s`) assigned to attribute (`%s`) does not implement `%s`, but its `@CollectionType` defined parameters", + implementation.getName(), + role, + ParameterizedType.class.getName() + ); + + // but still return the bean - we can again use the no-config bean instance + return beanRegistry.getBean( implementation ); + } + } + } + private static CollectionBinder createBinderFromProperty( XProperty property, MetadataBuildingContext buildingContext) { - final CollectionClassification classification = determineCollectionClassification( property, null, buildingContext ); - return createBinder( property, classification, null, buildingContext ); + final CollectionClassification classification = determineCollectionClassification( property, buildingContext ); + return createBinder( property, null, classification, buildingContext ); } private static CollectionBinder createBinderFromCustomTypeAnnotation( XProperty property, CollectionType typeAnnotation, MetadataBuildingContext buildingContext) { - final CollectionClassification classification = determineCollectionClassification( property, typeAnnotation, buildingContext ); - final SemanticsResolver semanticsResolver = (collectionType) -> new CustomCollectionTypeSemantics<>( collectionType, classification ); - return createBinder( property, classification, semanticsResolver, buildingContext ); + determineSemanticJavaType( property ); + + final ManagedBean customTypeBean = resolveCustomType( property, typeAnnotation, buildingContext ); + return createBinder( + property, + () -> customTypeBean, + customTypeBean.getBeanInstance().getClassification(), + buildingContext + ); + } + + public static ManagedBean resolveCustomType( + XProperty property, + CollectionType typeAnnotation, + MetadataBuildingContext buildingContext) { + final ManagedBeanRegistry beanRegistry = buildingContext.getBootstrapContext() + .getServiceRegistry() + .getService( ManagedBeanRegistry.class ); + + final Class typeImpl = typeAnnotation.type(); + if ( typeAnnotation.parameters().length == 0 ) { + // no parameters - we can re-use a no-config bean instance + return beanRegistry.getBean( typeImpl ); + } + else { + // defined parameters... + final String attributeKey = property.getDeclaringClass().getName() + "#" + property.getName(); + + if ( ParameterizedType.class.isAssignableFrom( typeImpl ) ) { + // because there are config parameters and the type is configurable, we need + // a separate bean instance which means uniquely naming it + final ManagedBean typeBean = beanRegistry.getBean( attributeKey, typeImpl ); + final UserCollectionType type = typeBean.getBeanInstance(); + ( (ParameterizedType) type ).setParameterValues( extractParameters( typeAnnotation ) ); + return typeBean; + } + else { + // log a "warning" + BootLogging.LOGGER.debugf( + "Custom collection-type (`%s`) assigned to attribute (`%s`) does not implement `%s`, but its `@CollectionType` defined parameters", + typeImpl.getName(), + attributeKey, + ParameterizedType.class.getName() + ); + + // but still return the bean - we can again use the no-config bean instance + return beanRegistry.getBean( typeImpl ); + } + } + } + + private static Properties extractParameters(CollectionType typeAnnotation) { + final Parameter[] parameterAnnotations = typeAnnotation.parameters(); + final Properties configParams = new Properties( parameterAnnotations.length ); + for ( Parameter parameterAnnotation : parameterAnnotations ) { + configParams.put( parameterAnnotation.name(), parameterAnnotation.value() ); + } + return configParams; } private static CollectionBinder createBinder( XProperty property, + Supplier> customTypeBeanAccess, CollectionClassification classification, - SemanticsResolver semanticsResolver, MetadataBuildingContext buildingContext) { - switch ( classification ) { case ARRAY: { if ( property.getElementClass().isPrimitive() ) { - return new PrimitiveArrayBinder( semanticsResolver, buildingContext ); + return new PrimitiveArrayBinder( customTypeBeanAccess, buildingContext ); } - return new ArrayBinder( semanticsResolver, buildingContext ); + return new ArrayBinder( customTypeBeanAccess, buildingContext ); } case BAG: { - return new BagBinder( semanticsResolver, buildingContext ); + return new BagBinder( customTypeBeanAccess, buildingContext ); } case ID_BAG: { - return new IdBagBinder( semanticsResolver, buildingContext ); + return new IdBagBinder( customTypeBeanAccess, buildingContext ); } case LIST: { - return new ListBinder( semanticsResolver, buildingContext ); + return new ListBinder( customTypeBeanAccess, buildingContext ); } case MAP: case ORDERED_MAP: { - return new MapBinder( semanticsResolver, false, buildingContext ); + return new MapBinder( customTypeBeanAccess, false, buildingContext ); } case SORTED_MAP: { - return new MapBinder( semanticsResolver, true, buildingContext ); + return new MapBinder( customTypeBeanAccess, true, buildingContext ); } case SET: case ORDERED_SET: { - return new SetBinder( semanticsResolver, false, buildingContext ); + return new SetBinder( customTypeBeanAccess, false, buildingContext ); } case SORTED_SET: { - return new SetBinder( semanticsResolver, true, buildingContext ); + return new SetBinder( customTypeBeanAccess, true, buildingContext ); } } @@ -392,23 +494,32 @@ public abstract class CollectionBinder { private static CollectionClassification determineCollectionClassification( XProperty property, - CollectionType typeAnnotation, MetadataBuildingContext buildingContext) { - final CollectionClassificationType classificationTypeAnnotation = property.getAnnotation( CollectionClassificationType.class ); - if ( property.isArray() ) { - if ( classificationTypeAnnotation != null ) { - throw new AnnotationException( "Arrays should not be annotated with `@" + CollectionClassificationType.class.getName() + "`" ); - } return CollectionClassification.ARRAY; } - if ( classificationTypeAnnotation != null ) { - return classificationTypeAnnotation.value(); + final Bag bagAnnotation = HCANNHelper.findAnnotation( property, Bag.class ); + if ( bagAnnotation != null ) { + final Class collectionJavaType = property.getCollectionClass(); + if ( java.util.List.class.equals( collectionJavaType ) || java.util.Collection.class.equals( collectionJavaType ) ) { + return CollectionClassification.BAG; + } + throw new MappingException( + String.format( + Locale.ROOT, + "@Bag annotation encountered on an attribute `%s#%s` of type `%s`; only `%s` and `%s` are supported", + property.getDeclaringClass().getName(), + property.getName(), + collectionJavaType.getName(), + java.util.List.class.getName(), + java.util.Collection.class.getName() + ) + ); } return determineCollectionClassification( - determineSemanticJavaType( property, typeAnnotation ), + determineSemanticJavaType( property ), property, buildingContext ); @@ -466,14 +577,7 @@ public abstract class CollectionBinder { } } - private static Class determineSemanticJavaType(XProperty property, CollectionType typeAnnotation) { - if ( typeAnnotation != null ) { - final Class requestedSemanticsJavaType = typeAnnotation.semantics(); - if ( requestedSemanticsJavaType != null && requestedSemanticsJavaType != void.class ) { - return inferCollectionClassFromSubclass( requestedSemanticsJavaType ); - } - } - + private static Class determineSemanticJavaType(XProperty property) { final Class returnedJavaType = property.getCollectionClass(); if ( returnedJavaType == null ) { throw new AnnotationException( diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/IdBagBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/IdBagBinder.java index 4258c81fa8..07896b9819 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/IdBagBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/IdBagBinder.java @@ -8,6 +8,7 @@ package org.hibernate.cfg.annotations; import java.util.Collections; import java.util.Map; +import java.util.function.Supplier; import org.hibernate.MappingException; import org.hibernate.annotations.CollectionId; @@ -24,10 +25,13 @@ import org.hibernate.cfg.SecondPass; import org.hibernate.cfg.WrappedInferredData; import org.hibernate.mapping.BasicValue; import org.hibernate.mapping.Collection; +import org.hibernate.mapping.IdentifierBag; import org.hibernate.mapping.IdentifierCollection; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.SemanticsResolver; import org.hibernate.mapping.Table; +import org.hibernate.resource.beans.spi.ManagedBean; +import org.hibernate.usertype.UserCollectionType; import jakarta.persistence.Column; @@ -35,12 +39,12 @@ import jakarta.persistence.Column; * @author Emmanuel Bernard */ public class IdBagBinder extends BagBinder { - public IdBagBinder(SemanticsResolver semanticsResolver, MetadataBuildingContext buildingContext) { - super( semanticsResolver, buildingContext ); + public IdBagBinder(Supplier> customTypeBeanResolver, MetadataBuildingContext buildingContext) { + super( customTypeBeanResolver, buildingContext ); } protected Collection createCollection(PersistentClass owner) { - return new org.hibernate.mapping.IdentifierBag( getSemanticsResolver(), owner, getBuildingContext() ); + return new IdentifierBag( getCustomTypeBeanResolver(), owner, getBuildingContext() ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/ListBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/ListBinder.java index ab7aa22b39..e3bd0a22d1 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/ListBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/ListBinder.java @@ -7,6 +7,7 @@ package org.hibernate.cfg.annotations; import java.util.Map; +import java.util.function.Supplier; import org.hibernate.MappingException; import org.hibernate.annotations.OrderBy; @@ -28,6 +29,8 @@ import org.hibernate.mapping.OneToMany; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.SemanticsResolver; import org.hibernate.mapping.SimpleValue; +import org.hibernate.resource.beans.spi.ManagedBean; +import org.hibernate.usertype.UserCollectionType; import org.jboss.logging.Logger; @@ -41,13 +44,13 @@ import org.jboss.logging.Logger; public class ListBinder extends CollectionBinder { private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, ListBinder.class.getName() ); - public ListBinder(SemanticsResolver semanticsResolver, MetadataBuildingContext buildingContext) { - super( semanticsResolver, false, buildingContext ); + public ListBinder(Supplier> customTypeBeanResolver, MetadataBuildingContext buildingContext) { + super( customTypeBeanResolver, false, buildingContext ); } @Override protected Collection createCollection(PersistentClass owner) { - return new List( getSemanticsResolver(), owner, getBuildingContext() ); + return new List( getCustomTypeBeanResolver(), owner, getBuildingContext() ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/MapBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/MapBinder.java index 77f817729a..a9a9277791 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/MapBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/MapBinder.java @@ -9,6 +9,7 @@ package org.hibernate.cfg.annotations; import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.function.Supplier; import org.hibernate.AnnotationException; import org.hibernate.AssertionFailure; @@ -48,6 +49,8 @@ import org.hibernate.mapping.SemanticsResolver; import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.Table; import org.hibernate.mapping.Value; +import org.hibernate.resource.beans.spi.ManagedBean; +import org.hibernate.usertype.UserCollectionType; import jakarta.persistence.AttributeOverride; import jakarta.persistence.AttributeOverrides; @@ -64,8 +67,8 @@ import jakarta.persistence.MapKeyJoinColumns; * @author Emmanuel Bernard */ public class MapBinder extends CollectionBinder { - public MapBinder(SemanticsResolver semanticsResolver, boolean sorted, MetadataBuildingContext buildingContext) { - super( semanticsResolver, sorted, buildingContext ); + public MapBinder(Supplier> customTypeBeanResolver, boolean sorted, MetadataBuildingContext buildingContext) { + super( customTypeBeanResolver, sorted, buildingContext ); } public boolean isMap() { @@ -73,7 +76,7 @@ public class MapBinder extends CollectionBinder { } protected Collection createCollection(PersistentClass owner) { - return new org.hibernate.mapping.Map( getSemanticsResolver(), owner, getBuildingContext() ); + return new org.hibernate.mapping.Map( getCustomTypeBeanResolver(), owner, getBuildingContext() ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/PrimitiveArrayBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/PrimitiveArrayBinder.java index 65dabed5a4..bc326e7707 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/PrimitiveArrayBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/PrimitiveArrayBinder.java @@ -6,22 +6,25 @@ */ package org.hibernate.cfg.annotations; +import java.util.function.Supplier; + import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.mapping.Collection; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.PrimitiveArray; -import org.hibernate.mapping.SemanticsResolver; +import org.hibernate.resource.beans.spi.ManagedBean; +import org.hibernate.usertype.UserCollectionType; /** * @author Emmanuel Bernard */ public class PrimitiveArrayBinder extends ArrayBinder { - public PrimitiveArrayBinder(SemanticsResolver semanticsResolver, MetadataBuildingContext buildingContext) { - super( semanticsResolver, buildingContext ); + public PrimitiveArrayBinder(Supplier> customTypeBeanResolver, MetadataBuildingContext buildingContext) { + super( customTypeBeanResolver, buildingContext ); } @Override protected Collection createCollection(PersistentClass owner) { - return new PrimitiveArray( getSemanticsResolver(), owner, getBuildingContext() ); + return new PrimitiveArray( getCustomTypeBeanResolver(), owner, getBuildingContext() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/SetBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/SetBinder.java index a17b348595..a895be08a3 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/SetBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/SetBinder.java @@ -6,11 +6,15 @@ */ package org.hibernate.cfg.annotations; +import java.util.function.Supplier; + import org.hibernate.annotations.OrderBy; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.mapping.Collection; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.SemanticsResolver; +import org.hibernate.resource.beans.spi.ManagedBean; +import org.hibernate.usertype.UserCollectionType; /** * Bind a set. @@ -18,13 +22,13 @@ import org.hibernate.mapping.SemanticsResolver; * @author Matthew Inger */ public class SetBinder extends CollectionBinder { - public SetBinder(SemanticsResolver semanticsResolver, boolean sorted, MetadataBuildingContext buildingContext) { - super( semanticsResolver, sorted, buildingContext ); + public SetBinder(Supplier> customTypeBeanResolver, boolean sorted, MetadataBuildingContext buildingContext) { + super( customTypeBeanResolver, sorted, buildingContext ); } @Override protected Collection createCollection(PersistentClass persistentClass) { - return new org.hibernate.mapping.Set( getSemanticsResolver(), persistentClass, getBuildingContext() ); + return new org.hibernate.mapping.Set( getCustomTypeBeanResolver(), persistentClass, getBuildingContext() ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/CustomCollectionTypeSemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/CustomCollectionTypeSemantics.java index 287c78553a..30a770cb1a 100644 --- a/hibernate-core/src/main/java/org/hibernate/collection/internal/CustomCollectionTypeSemantics.java +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/CustomCollectionTypeSemantics.java @@ -30,16 +30,18 @@ import org.hibernate.type.CollectionType; */ public class CustomCollectionTypeSemantics implements CollectionSemantics { private final CollectionType collectionType; - private final CollectionClassification classification; - public CustomCollectionTypeSemantics(CollectionType collectionType, CollectionClassification classification) { + public CustomCollectionTypeSemantics(CollectionType collectionType) { this.collectionType = collectionType; - this.classification = classification; + } + + public CollectionType getCollectionType() { + return collectionType; } @Override public CollectionClassification getCollectionClassification() { - return classification; + return collectionType.getCollectionClassification(); } @Override @@ -77,7 +79,7 @@ public class CustomCollectionTypeSemantics implements CollectionSemantics return InitializerProducerBuilder.createCollectionTypeWrapperInitializerProducer( navigablePath, attributeMapping, - classification, + getCollectionClassification(), fetchParent, selected, indexFetch, diff --git a/hibernate-core/src/main/java/org/hibernate/collection/spi/CollectionInitializerProducer.java b/hibernate-core/src/main/java/org/hibernate/collection/spi/CollectionInitializerProducer.java index 48b335228f..a732b24aa6 100644 --- a/hibernate-core/src/main/java/org/hibernate/collection/spi/CollectionInitializerProducer.java +++ b/hibernate-core/src/main/java/org/hibernate/collection/spi/CollectionInitializerProducer.java @@ -6,33 +6,39 @@ */ package org.hibernate.collection.spi; -import java.util.function.Consumer; - import org.hibernate.Incubating; import org.hibernate.LockMode; import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.query.NavigablePath; -import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.results.graph.AssemblerCreationState; -import org.hibernate.sql.results.graph.collection.CollectionInitializer; import org.hibernate.sql.results.graph.DomainResultAssembler; import org.hibernate.sql.results.graph.FetchParentAccess; -import org.hibernate.sql.results.graph.Initializer; +import org.hibernate.sql.results.graph.collection.CollectionInitializer; /** * Functional contract to create a CollectionInitializer * * @author Steve Ebersole + * + * @since 6.0 */ @Incubating @FunctionalInterface public interface CollectionInitializerProducer { /** - * todo (6.0) : clean this contract up! + * Create an initializer for `attribute` relative to `navigablePath`. + * + * `parentAccess` may be null to indicate that the initializer is for + * a {@link org.hibernate.sql.results.graph.DomainResult} rather than + * a {@link org.hibernate.sql.results.graph.Fetch} + * + * `collectionKeyAssembler` and `collectionValueKeyAssembler` allow + * creating {@link org.hibernate.sql.results.graph.DomainResult} for + * either side of the collection foreign-key */ CollectionInitializer produceInitializer( NavigablePath navigablePath, - PluralAttributeMapping attributeMapping, + PluralAttributeMapping attribute, FetchParentAccess parentAccess, LockMode lockMode, DomainResultAssembler collectionKeyAssembler, diff --git a/hibernate-core/src/main/java/org/hibernate/collection/spi/CollectionSemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/spi/CollectionSemantics.java index f9f271917c..b012d3a964 100644 --- a/hibernate-core/src/main/java/org/hibernate/collection/spi/CollectionSemantics.java +++ b/hibernate-core/src/main/java/org/hibernate/collection/spi/CollectionSemantics.java @@ -27,6 +27,8 @@ import org.hibernate.sql.results.graph.FetchParent; * * @author Steve Ebersole * @author Gavin King + * + * @since 6.0 */ @Incubating public interface CollectionSemantics { diff --git a/hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentBag.java b/hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentBag.java index 88e932214a..86255aac67 100644 --- a/hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentBag.java +++ b/hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentBag.java @@ -500,7 +500,7 @@ public class PersistentBag extends AbstractPersistentCollection implements @Override public Object getIndex(Object entry, int i, CollectionPersister persister) { - throw new UnsupportedOperationException( "Bags don't have indexes" ); + throw new UnsupportedOperationException( "Bags don't have indexes : " + persister.getRole() ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Array.java b/hibernate-core/src/main/java/org/hibernate/mapping/Array.java index 315435c9ca..f9e4e991a2 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Array.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Array.java @@ -6,7 +6,7 @@ */ package org.hibernate.mapping; -import java.util.function.Function; +import java.util.function.Supplier; import org.hibernate.MappingException; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; @@ -14,10 +14,12 @@ import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.collection.internal.StandardArraySemantics; import org.hibernate.collection.spi.CollectionSemantics; +import org.hibernate.resource.beans.spi.ManagedBean; import org.hibernate.type.ArrayType; import org.hibernate.type.BasicType; import org.hibernate.type.CollectionType; import org.hibernate.type.descriptor.java.spi.PrimitiveJavaType; +import org.hibernate.usertype.UserCollectionType; /** * An array mapping has a primary key consisting of the key columns + index column. @@ -31,8 +33,8 @@ public class Array extends List { super( buildingContext, owner ); } - public Array(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) { - super( semanticsResolver, owner, buildingContext ); + public Array(Supplier> customTypeBeanResolver, PersistentClass owner, MetadataBuildingContext buildingContext) { + super( customTypeBeanResolver, owner, buildingContext ); } public Class getElementClass() throws MappingException { diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Bag.java b/hibernate-core/src/main/java/org/hibernate/mapping/Bag.java index 39b825936b..4d0478f921 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Bag.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Bag.java @@ -7,12 +7,15 @@ package org.hibernate.mapping; import java.util.function.Function; +import java.util.function.Supplier; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.collection.internal.StandardBagSemantics; import org.hibernate.collection.spi.CollectionSemantics; +import org.hibernate.resource.beans.spi.ManagedBean; import org.hibernate.type.BagType; import org.hibernate.type.CollectionType; +import org.hibernate.usertype.UserCollectionType; /** * A bag permits duplicates, so it has no primary key @@ -30,8 +33,8 @@ public class Bag extends Collection { /** * Annotation binding */ - public Bag(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) { - super( semanticsResolver, owner, buildingContext ); + public Bag(Supplier> customTypeBeanResolver, PersistentClass owner, MetadataBuildingContext buildingContext) { + super( customTypeBeanResolver, owner, buildingContext ); } public CollectionType getDefaultCollectionType() { diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Collection.java b/hibernate-core/src/main/java/org/hibernate/mapping/Collection.java index 7aceb706d8..51572ff6e3 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Collection.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Collection.java @@ -14,8 +14,7 @@ import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.Properties; -import java.util.SortedMap; -import java.util.SortedSet; +import java.util.function.Supplier; import org.hibernate.FetchMode; import org.hibernate.MappingException; @@ -29,12 +28,14 @@ import org.hibernate.engine.spi.Mapping; import org.hibernate.internal.FilterConfiguration; import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.ArrayHelper; -import org.hibernate.metamodel.CollectionClassification; import org.hibernate.persister.collection.CollectionPersister; +import org.hibernate.resource.beans.spi.ManagedBean; import org.hibernate.service.ServiceRegistry; import org.hibernate.type.CollectionType; +import org.hibernate.type.CustomCollectionType; import org.hibernate.type.Type; import org.hibernate.type.spi.TypeConfiguration; +import org.hibernate.usertype.UserCollectionType; /** * Mapping for a collection. Subclasses specialize to particular collection styles. @@ -77,7 +78,10 @@ public abstract class Collection implements Fetchable, Value, Filterable { private String typeName; private Properties typeParameters; - private SemanticsResolver customSemanticsResolver; + private Supplier> customTypeBeanResolver; + private CollectionType cachedCollectionType; + private CollectionSemantics cachedCollectionSemantics; + private Class collectionPersisterClass; private final List filters = new ArrayList<>(); @@ -110,8 +114,11 @@ public abstract class Collection implements Fetchable, Value, Filterable { /** * Annotation binding */ - protected Collection(SemanticsResolver customSemanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) { - this.customSemanticsResolver = customSemanticsResolver; + protected Collection( + Supplier> customTypeBeanResolver, + PersistentClass owner, + MetadataBuildingContext buildingContext) { + this.customTypeBeanResolver = customTypeBeanResolver; this.owner = owner; this.buildingContext = buildingContext; } @@ -409,8 +416,6 @@ public abstract class Collection implements Fetchable, Value, Filterable { return getCollectionType(); } - private CollectionSemantics cachedCollectionSemantics; - @SuppressWarnings("rawtypes") public CollectionSemantics getCollectionSemantics() { if ( cachedCollectionSemantics == null ) { @@ -422,8 +427,32 @@ public abstract class Collection implements Fetchable, Value, Filterable { private CollectionSemantics resolveCollectionSemantics() { final CollectionType collectionType; - if ( typeName == null ) { - collectionType = null; + if ( cachedCollectionType == null ) { + collectionType = resolveCollectionType(); + cachedCollectionType = collectionType; + } + else { + collectionType = cachedCollectionType; + } + + return new CustomCollectionTypeSemantics<>( collectionType ); + } + + private CollectionType resolveCollectionType() { + final CollectionType collectionType; + if ( cachedCollectionType != null ) { + collectionType = cachedCollectionType; + } + else if ( customTypeBeanResolver != null ) { + collectionType = new CustomCollectionType( + customTypeBeanResolver.get(), + role, + referencedPropertyName, + getMetadata().getTypeConfiguration() + ); + } + else if ( typeName == null ) { + collectionType = getDefaultCollectionType(); } else { collectionType = MappingHelper.customCollection( @@ -434,50 +463,7 @@ public abstract class Collection implements Fetchable, Value, Filterable { getMetadata() ); } - - if ( customSemanticsResolver != null ) { - return customSemanticsResolver.resolve( collectionType ); - } - - if ( collectionType == null ) { - return getDefaultCollectionSemantics(); - } - - final Class semanticJavaType = collectionType.getReturnedClass(); - final CollectionClassification classification; - - if ( semanticJavaType.isArray() ) { - classification = CollectionClassification.ARRAY; - } - else if ( List.class.isAssignableFrom( semanticJavaType ) ) { - classification = CollectionClassification.LIST; - } - else if ( SortedSet.class.isAssignableFrom( semanticJavaType ) ) { - classification = CollectionClassification.SORTED_SET; - } - else if ( Set.class.isAssignableFrom( semanticJavaType ) ) { - classification = CollectionClassification.SET; - } - else if ( SortedMap.class.isAssignableFrom( semanticJavaType ) ) { - classification = CollectionClassification.SORTED_MAP; - } - else if ( Map.class.isAssignableFrom( semanticJavaType ) ) { - classification = CollectionClassification.MAP; - } - else if ( Collection.class.isAssignableFrom( semanticJavaType ) ) { - if ( isIdentified() ) { - classification = CollectionClassification.ID_BAG; - } - else { - classification = CollectionClassification.BAG; - } - } - else { - throw new IllegalArgumentException( "Unexpected collection-semantics Java type : " + semanticJavaType ); - } - - return new CustomCollectionTypeSemantics<>( collectionType, classification ); - + return collectionType; } public CollectionSemantics getDefaultCollectionSemantics() { @@ -488,13 +474,10 @@ public abstract class Collection implements Fetchable, Value, Filterable { } public CollectionType getCollectionType() { - // todo (6.0) : hook in CollectionSemantics - if ( typeName == null ) { - return getDefaultCollectionType(); - } - else { - return MappingHelper.customCollection( typeName, typeParameters, role, referencedPropertyName, getMetadata() ); + if ( cachedCollectionType == null ) { + cachedCollectionType = resolveCollectionType(); } + return cachedCollectionType; } public boolean isNullable() { diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/IdentifierBag.java b/hibernate-core/src/main/java/org/hibernate/mapping/IdentifierBag.java index cf95854527..ccb1d3631b 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/IdentifierBag.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/IdentifierBag.java @@ -6,11 +6,15 @@ */ package org.hibernate.mapping; +import java.util.function.Supplier; + import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.collection.internal.StandardIdentifierBagSemantics; import org.hibernate.collection.spi.CollectionSemantics; +import org.hibernate.resource.beans.spi.ManagedBean; import org.hibernate.type.CollectionType; import org.hibernate.type.IdentifierBagType; +import org.hibernate.usertype.UserCollectionType; /** * An {@code IdentifierBag} has a primary key consisting of @@ -28,8 +32,8 @@ public class IdentifierBag extends IdentifierCollection { /** * annotation binding */ - public IdentifierBag(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) { - super( semanticsResolver, owner, buildingContext ); + public IdentifierBag(Supplier> customTypeBeanResolver, PersistentClass owner, MetadataBuildingContext buildingContext) { + super( customTypeBeanResolver, owner, buildingContext ); } public CollectionType getDefaultCollectionType() { diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/IdentifierCollection.java b/hibernate-core/src/main/java/org/hibernate/mapping/IdentifierCollection.java index ea19bbc5bc..5d9c36d072 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/IdentifierCollection.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/IdentifierCollection.java @@ -6,10 +6,13 @@ */ package org.hibernate.mapping; +import java.util.function.Supplier; + import org.hibernate.MappingException; import org.hibernate.boot.spi.MetadataBuildingContext; -import org.hibernate.collection.spi.CollectionSemantics; import org.hibernate.engine.spi.Mapping; +import org.hibernate.resource.beans.spi.ManagedBean; +import org.hibernate.usertype.UserCollectionType; /** * A collection with a synthetic "identifier" column @@ -24,8 +27,8 @@ public abstract class IdentifierCollection extends Collection { super( buildingContext, owner ); } - public IdentifierCollection(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) { - super( semanticsResolver, owner, buildingContext ); + public IdentifierCollection(Supplier> customTypeBeanResolver, PersistentClass owner, MetadataBuildingContext buildingContext) { + super( customTypeBeanResolver, owner, buildingContext ); } public KeyValue getIdentifier() { diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/IndexedCollection.java b/hibernate-core/src/main/java/org/hibernate/mapping/IndexedCollection.java index f5c750d81f..7627f0e5b2 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/IndexedCollection.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/IndexedCollection.java @@ -7,13 +7,13 @@ package org.hibernate.mapping; import java.util.Iterator; -import java.util.function.Function; +import java.util.function.Supplier; import org.hibernate.MappingException; import org.hibernate.boot.spi.MetadataBuildingContext; -import org.hibernate.collection.spi.CollectionSemantics; import org.hibernate.engine.spi.Mapping; -import org.hibernate.type.CollectionType; +import org.hibernate.resource.beans.spi.ManagedBean; +import org.hibernate.usertype.UserCollectionType; /** * Indexed collections include Lists, Maps, arrays and @@ -30,8 +30,8 @@ public abstract class IndexedCollection extends Collection { super( buildingContext, owner ); } - public IndexedCollection(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) { - super( semanticsResolver, owner, buildingContext ); + public IndexedCollection(Supplier> customTypeBeanResolver, PersistentClass owner, MetadataBuildingContext buildingContext) { + super( customTypeBeanResolver, owner, buildingContext ); } public Value getIndex() { diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/List.java b/hibernate-core/src/main/java/org/hibernate/mapping/List.java index 7b5bc4056e..ca4ae6839b 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/List.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/List.java @@ -6,14 +6,16 @@ */ package org.hibernate.mapping; -import java.util.function.Function; +import java.util.function.Supplier; import org.hibernate.MappingException; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.collection.internal.StandardListSemantics; import org.hibernate.collection.spi.CollectionSemantics; +import org.hibernate.resource.beans.spi.ManagedBean; import org.hibernate.type.CollectionType; import org.hibernate.type.ListType; +import org.hibernate.usertype.UserCollectionType; /** * A list mapping has a primary key consisting of the key columns + index column. @@ -34,8 +36,8 @@ public class List extends IndexedCollection { /** * annotation binding */ - public List(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) { - super( semanticsResolver, owner, buildingContext ); + public List(Supplier> customTypeBeanResolver, PersistentClass owner, MetadataBuildingContext buildingContext) { + super( customTypeBeanResolver, owner, buildingContext ); } public boolean isList() { diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Map.java b/hibernate-core/src/main/java/org/hibernate/mapping/Map.java index eea3205244..da3f813e50 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Map.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Map.java @@ -6,16 +6,20 @@ */ package org.hibernate.mapping; +import java.util.function.Supplier; + import org.hibernate.MappingException; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.collection.internal.StandardMapSemantics; import org.hibernate.collection.internal.StandardOrderedMapSemantics; import org.hibernate.collection.internal.StandardSortedMapSemantics; import org.hibernate.collection.spi.CollectionSemantics; +import org.hibernate.resource.beans.spi.ManagedBean; import org.hibernate.type.CollectionType; import org.hibernate.type.MapType; import org.hibernate.type.OrderedMapType; import org.hibernate.type.SortedMapType; +import org.hibernate.usertype.UserCollectionType; /** * A map has a primary key consisting of @@ -29,8 +33,8 @@ public class Map extends IndexedCollection { super( buildingContext, owner ); } - public Map(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) { - super( semanticsResolver, owner, buildingContext ); + public Map(Supplier> customTypeBeanResolver, PersistentClass owner, MetadataBuildingContext buildingContext) { + super( customTypeBeanResolver, owner, buildingContext ); } public boolean isMap() { diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/MappingHelper.java b/hibernate-core/src/main/java/org/hibernate/mapping/MappingHelper.java index 07d7a1bc35..d6ce2ba5da 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/MappingHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/MappingHelper.java @@ -6,18 +6,17 @@ */ package org.hibernate.mapping; -import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.function.Supplier; import org.hibernate.Internal; -import org.hibernate.MappingException; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; -import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.metamodel.mapping.MappingModelCreationLogger; +import org.hibernate.resource.beans.spi.ManagedBean; +import org.hibernate.resource.beans.spi.ManagedBeanRegistry; import org.hibernate.type.AnyType; import org.hibernate.type.CollectionType; import org.hibernate.type.CustomCollectionType; @@ -47,20 +46,23 @@ public final class MappingHelper { String propertyRef, MetadataImplementor metadata) { final ClassLoaderService cls = metadata.getMetadataBuildingOptions().getServiceRegistry().getService( ClassLoaderService.class ); + final Class typeImpl = cls.classForName( typeName ); - try { - final Class typeClass = cls.classForName( typeName ); + final ManagedBeanRegistry beanRegistry = metadata + .getMetadataBuildingOptions() + .getServiceRegistry() + .getService( ManagedBeanRegistry.class ); - CustomCollectionType result = new CustomCollectionType( typeClass, role, propertyRef, metadata.getTypeConfiguration() ); - if ( typeParameters != null ) { - injectParameters( result.getUserType(), typeParameters ); - } - - return result; + final ManagedBean customTypeBean; + if ( typeParameters == null ) { + customTypeBean = beanRegistry.getBean( typeImpl ); } - catch (ClassLoadingException e) { - throw new MappingException( "user collection type class not found: " + typeName, e ); + else { + customTypeBean = beanRegistry.getBean( role, typeImpl ); + injectParameters( customTypeBean.getBeanInstance(), typeParameters ); } + + return new CustomCollectionType( customTypeBean, role, propertyRef, metadata.getTypeConfiguration() ); } public static void injectParameters(Object type, Properties parameters) { diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/PrimitiveArray.java b/hibernate-core/src/main/java/org/hibernate/mapping/PrimitiveArray.java index 5b94b100f9..b2ed7c4ccc 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/PrimitiveArray.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/PrimitiveArray.java @@ -6,9 +6,13 @@ */ package org.hibernate.mapping; +import java.util.function.Supplier; + import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.collection.internal.StandardArraySemantics; import org.hibernate.collection.spi.CollectionSemantics; +import org.hibernate.resource.beans.spi.ManagedBean; +import org.hibernate.usertype.UserCollectionType; /** * A primitive array has a primary key consisting of the key columns + index column. @@ -18,8 +22,8 @@ public class PrimitiveArray extends Array { super( buildingContext, owner ); } - public PrimitiveArray(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) { - super( semanticsResolver, owner, buildingContext ); + public PrimitiveArray(Supplier> customTypeBeanResolver, PersistentClass owner, MetadataBuildingContext buildingContext) { + super( customTypeBeanResolver, owner, buildingContext ); } public boolean isPrimitiveArray() { diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Set.java b/hibernate-core/src/main/java/org/hibernate/mapping/Set.java index 1f8e7b9b70..0f949355be 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Set.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Set.java @@ -7,6 +7,7 @@ package org.hibernate.mapping; import java.util.Iterator; +import java.util.function.Supplier; import org.hibernate.MappingException; import org.hibernate.boot.spi.MetadataBuildingContext; @@ -15,10 +16,12 @@ import org.hibernate.collection.internal.StandardSetSemantics; import org.hibernate.collection.internal.StandardSortedSetSemantics; import org.hibernate.collection.spi.CollectionSemantics; import org.hibernate.engine.spi.Mapping; +import org.hibernate.resource.beans.spi.ManagedBean; import org.hibernate.type.CollectionType; import org.hibernate.type.OrderedSetType; import org.hibernate.type.SetType; import org.hibernate.type.SortedSetType; +import org.hibernate.usertype.UserCollectionType; /** * A set with no nullable element columns. It will have a primary key @@ -36,8 +39,8 @@ public class Set extends Collection { /** * Used by annotation binding */ - public Set(SemanticsResolver semanticsResolver, PersistentClass persistentClass, MetadataBuildingContext buildingContext) { - super( semanticsResolver, persistentClass, buildingContext ); + public Set(Supplier> customTypeBeanResolver, PersistentClass persistentClass, MetadataBuildingContext buildingContext) { + super( customTypeBeanResolver, persistentClass, buildingContext ); } public void validate(Mapping mapping) throws MappingException { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/CollectionClassification.java b/hibernate-core/src/main/java/org/hibernate/metamodel/CollectionClassification.java index d4fa9f75e6..04dd38809a 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/CollectionClassification.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/CollectionClassification.java @@ -56,6 +56,9 @@ public enum CollectionClassification { * A sorted {@link #SET} using either natural sorting of the elements or a * specified {@link java.util.Comparator}. Represented * as {@link java.util.SortedSet} or {@link java.util.Set} + * + * @see org.hibernate.annotations.SortNatural + * @see org.hibernate.annotations.SortComparator */ SORTED_SET( PluralAttribute.CollectionType.SET ), @@ -64,6 +67,9 @@ public enum CollectionClassification { * as the collection is loaded. Does not maintain ordering * while in memory if the contents change. Represented * as {@link java.util.Set}. + * + * @see jakarta.persistence.OrderBy + * @see org.hibernate.annotations.OrderBy */ ORDERED_SET( PluralAttribute.CollectionType.SET ), @@ -76,6 +82,9 @@ public enum CollectionClassification { * A sorted {@link #MAP} using either natural sorting of the keys or a * specified {@link java.util.Comparator}. Represented * as {@link java.util.SortedMap} or {@link java.util.Map} + * + * @see org.hibernate.annotations.SortNatural + * @see org.hibernate.annotations.SortComparator */ SORTED_MAP( PluralAttribute.CollectionType.MAP ), @@ -84,6 +93,9 @@ public enum CollectionClassification { * as the collection is loaded. Does not maintain ordering * while in memory if the contents change. Represented * as {@link java.util.Map}. + * + * @see jakarta.persistence.OrderBy + * @see org.hibernate.annotations.OrderBy */ ORDERED_MAP( PluralAttribute.CollectionType.MAP ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoBasicStandard.java b/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoBasicStandard.java index 7850de7f0a..a525d4ca26 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoBasicStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoBasicStandard.java @@ -7,7 +7,6 @@ package org.hibernate.query.internal; import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; import java.util.function.Consumer; import org.hibernate.boot.model.convert.internal.ConverterHelper; @@ -118,7 +117,7 @@ public class ResultMementoBasicStandard implements ResultMementoBasic { } else if ( UserType.class.isAssignableFrom( registeredJtd.getJavaTypeClass() ) ) { final ManagedBean> userTypeBean = (ManagedBean) beanRegistry.getBean( registeredJtd.getJavaTypeClass() ); - // todo (6.0) : is this the best approach? or should we keep a Class -> CustomType mapping somewhere? + // todo (6.0) : is this the best approach? or should we keep a Class -> @Type mapping somewhere? explicitType = new CustomType<>( (UserType) userTypeBean.getBeanInstance(), typeConfiguration ); explicitJavaTypeDescriptor = explicitType.getJavaTypeDescriptor(); } @@ -135,8 +134,8 @@ public class ResultMementoBasicStandard implements ResultMementoBasic { private BasicJavaType determineDomainJavaType( ParameterizedType parameterizedType, JavaTypeRegistry jtdRegistry) { - final Type[] typeParameters = parameterizedType.getActualTypeArguments(); - final Type domainTypeType = typeParameters[ 0 ]; + final java.lang.reflect.Type[] typeParameters = parameterizedType.getActualTypeArguments(); + final java.lang.reflect.Type domainTypeType = typeParameters[ 0 ]; final Class domainClass = (Class) domainTypeType; return (BasicJavaType) jtdRegistry.getDescriptor( domainClass ); @@ -145,7 +144,7 @@ public class ResultMementoBasicStandard implements ResultMementoBasic { private BasicValuedMapping resolveUnderlyingMapping( ParameterizedType parameterizedType, TypeConfiguration typeConfiguration) { - final Type[] typeParameters = parameterizedType.getActualTypeArguments(); + final java.lang.reflect.Type[] typeParameters = parameterizedType.getActualTypeArguments(); return typeConfiguration.standardBasicTypeForJavaType( (Class) typeParameters[ 1 ] ); } diff --git a/hibernate-core/src/main/java/org/hibernate/type/ArrayType.java b/hibernate-core/src/main/java/org/hibernate/type/ArrayType.java index 344e86dd70..a49149e7bf 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/ArrayType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/ArrayType.java @@ -20,6 +20,7 @@ import org.hibernate.collection.spi.PersistentArrayHolder; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.metamodel.CollectionClassification; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.type.spi.TypeConfiguration; @@ -43,6 +44,11 @@ public class ArrayType extends CollectionType { return arrayClass; } + @Override + public CollectionClassification getCollectionClassification() { + return CollectionClassification.ARRAY; + } + @Override public PersistentCollection instantiate(SharedSessionContractImplementor session, CollectionPersister persister, Object key) throws HibernateException { diff --git a/hibernate-core/src/main/java/org/hibernate/type/BagType.java b/hibernate-core/src/main/java/org/hibernate/type/BagType.java index 99f3f33adb..18aac65752 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/BagType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/BagType.java @@ -13,6 +13,7 @@ import org.hibernate.HibernateException; import org.hibernate.collection.spi.PersistentBag; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.metamodel.CollectionClassification; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.type.spi.TypeConfiguration; @@ -23,9 +24,8 @@ public class BagType extends CollectionType { } @Override - public PersistentCollection instantiate(SharedSessionContractImplementor session, CollectionPersister persister, Object key) - throws HibernateException { - return new PersistentBag( session ); + public CollectionClassification getCollectionClassification() { + return CollectionClassification.BAG; } @Override @@ -33,6 +33,12 @@ public class BagType extends CollectionType { return Collection.class; } + @Override + public PersistentCollection instantiate(SharedSessionContractImplementor session, CollectionPersister persister, Object key) + throws HibernateException { + return new PersistentBag( session ); + } + @Override public PersistentCollection wrap(SharedSessionContractImplementor session, Object collection) { return new PersistentBag( session, (Collection) collection ); diff --git a/hibernate-core/src/main/java/org/hibernate/type/CollectionType.java b/hibernate-core/src/main/java/org/hibernate/type/CollectionType.java index 334597ea83..1f677bcce4 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/CollectionType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/CollectionType.java @@ -37,6 +37,7 @@ import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.MarkerObject; import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.metamodel.CollectionClassification; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.QueryableCollection; import org.hibernate.persister.entity.EntityPersister; @@ -74,6 +75,8 @@ public abstract class CollectionType extends AbstractType implements Association this.foreignKeyPropertyName = foreignKeyPropertyName; } + public abstract CollectionClassification getCollectionClassification(); + public String getRole() { return role; } diff --git a/hibernate-core/src/main/java/org/hibernate/type/CustomCollectionType.java b/hibernate-core/src/main/java/org/hibernate/type/CustomCollectionType.java index 0107bcd336..a2296ff373 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/CustomCollectionType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/CustomCollectionType.java @@ -10,11 +10,12 @@ import java.util.Iterator; import java.util.Map; import org.hibernate.HibernateException; -import org.hibernate.MappingException; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.metamodel.CollectionClassification; import org.hibernate.persister.collection.CollectionPersister; +import org.hibernate.resource.beans.spi.ManagedBean; import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.usertype.LoggableUserType; import org.hibernate.usertype.UserCollectionType; @@ -32,30 +33,24 @@ public class CustomCollectionType extends CollectionType { private final boolean customLogging; public CustomCollectionType( - Class userTypeClass, + ManagedBean userTypeBean, String role, String foreignKeyPropertyName, TypeConfiguration typeConfiguration) { super( typeConfiguration, role, foreignKeyPropertyName ); - if ( !UserCollectionType.class.isAssignableFrom( userTypeClass ) ) { - throw new MappingException( "Custom type does not implement UserCollectionType: " + userTypeClass.getName() ); - } - - userType = createUserCollectionType( userTypeClass ); + userType = userTypeBean.getBeanInstance(); customLogging = userType instanceof LoggableUserType; } - private static UserCollectionType createUserCollectionType(Class userTypeClass) { - try { - return userTypeClass.newInstance(); - } - catch (InstantiationException ie) { - throw new MappingException( "Cannot instantiate custom type: " + userTypeClass.getName() ); - } - catch (IllegalAccessException iae) { - throw new MappingException( "IllegalAccessException trying to instantiate custom type: " + userTypeClass.getName() ); - } + @Override + public Class getReturnedClass() { + return userType.instantiate( -1 ).getClass(); + } + + @Override + public CollectionClassification getCollectionClassification() { + return userType.getClassification(); } @Override @@ -69,11 +64,6 @@ public class CustomCollectionType extends CollectionType { return userType.wrap( session, collection ); } - @Override - public Class getReturnedClass() { - return userType.instantiate( -1 ).getClass(); - } - @Override public Object instantiate(int anticipatedType) { return userType.instantiate( anticipatedType ); diff --git a/hibernate-core/src/main/java/org/hibernate/type/IdentifierBagType.java b/hibernate-core/src/main/java/org/hibernate/type/IdentifierBagType.java index 9f2cd5b926..c0205c3802 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/IdentifierBagType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/IdentifierBagType.java @@ -12,6 +12,7 @@ import org.hibernate.HibernateException; import org.hibernate.collection.spi.PersistentIdentifierBag; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.metamodel.CollectionClassification; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.type.spi.TypeConfiguration; @@ -21,6 +22,11 @@ public class IdentifierBagType extends CollectionType { super( typeConfiguration, role, propertyRef ); } + @Override + public CollectionClassification getCollectionClassification() { + return CollectionClassification.ID_BAG; + } + @Override public PersistentCollection instantiate( SharedSessionContractImplementor session, diff --git a/hibernate-core/src/main/java/org/hibernate/type/ListType.java b/hibernate-core/src/main/java/org/hibernate/type/ListType.java index d111790b3b..3e5e3d64c4 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/ListType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/ListType.java @@ -12,15 +12,23 @@ import java.util.List; import org.hibernate.collection.spi.PersistentList; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.metamodel.CollectionClassification; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.type.spi.TypeConfiguration; +import static org.hibernate.metamodel.CollectionClassification.LIST; + public class ListType extends CollectionType { public ListType(TypeConfiguration typeConfiguration, String role, String propertyRef) { super( typeConfiguration, role, propertyRef ); } + @Override + public CollectionClassification getCollectionClassification() { + return LIST; + } + @Override public PersistentCollection instantiate(SharedSessionContractImplementor session, CollectionPersister persister, Object key) { return new PersistentList( session ); diff --git a/hibernate-core/src/main/java/org/hibernate/type/MapType.java b/hibernate-core/src/main/java/org/hibernate/type/MapType.java index bf15444bc4..077f3a4cd7 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/MapType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/MapType.java @@ -14,6 +14,7 @@ import org.hibernate.HibernateException; import org.hibernate.collection.spi.PersistentMap; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.metamodel.CollectionClassification; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.type.spi.TypeConfiguration; @@ -24,6 +25,11 @@ public class MapType extends CollectionType { super( typeConfiguration, role, propertyRef ); } + @Override + public CollectionClassification getCollectionClassification() { + return CollectionClassification.MAP; + } + @Override public PersistentCollection instantiate( SharedSessionContractImplementor session, diff --git a/hibernate-core/src/main/java/org/hibernate/type/OrderedMapType.java b/hibernate-core/src/main/java/org/hibernate/type/OrderedMapType.java index 0a158e398a..ac7c8cec88 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/OrderedMapType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/OrderedMapType.java @@ -7,6 +7,7 @@ package org.hibernate.type; import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.metamodel.CollectionClassification; import org.hibernate.type.spi.TypeConfiguration; /** @@ -18,6 +19,11 @@ public class OrderedMapType extends MapType { super( typeConfiguration, role, propertyRef ); } + @Override + public CollectionClassification getCollectionClassification() { + return CollectionClassification.ORDERED_MAP; + } + @Override public Object instantiate(int anticipatedSize) { return anticipatedSize > 0 diff --git a/hibernate-core/src/main/java/org/hibernate/type/OrderedSetType.java b/hibernate-core/src/main/java/org/hibernate/type/OrderedSetType.java index a3fdbc74af..904de27a3b 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/OrderedSetType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/OrderedSetType.java @@ -7,6 +7,7 @@ package org.hibernate.type; import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.metamodel.CollectionClassification; import org.hibernate.type.spi.TypeConfiguration; /** @@ -18,6 +19,11 @@ public class OrderedSetType extends SetType { super( typeConfiguration, role, propertyRef ); } + @Override + public CollectionClassification getCollectionClassification() { + return CollectionClassification.ORDERED_SET; + } + @Override public Object instantiate(int anticipatedSize) { return anticipatedSize > 0 diff --git a/hibernate-core/src/main/java/org/hibernate/type/SetType.java b/hibernate-core/src/main/java/org/hibernate/type/SetType.java index eb16214b12..a920904482 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/SetType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/SetType.java @@ -10,6 +10,7 @@ import org.hibernate.collection.spi.PersistentSet; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.metamodel.CollectionClassification; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.type.spi.TypeConfiguration; @@ -20,8 +21,8 @@ public class SetType extends CollectionType { } @Override - public PersistentCollection instantiate(SharedSessionContractImplementor session, CollectionPersister persister, Object key) { - return new PersistentSet( session ); + public CollectionClassification getCollectionClassification() { + return CollectionClassification.SET; } @Override @@ -29,6 +30,11 @@ public class SetType extends CollectionType { return java.util.Set.class; } + @Override + public PersistentCollection instantiate(SharedSessionContractImplementor session, CollectionPersister persister, Object key) { + return new PersistentSet( session ); + } + @Override public PersistentCollection wrap(SharedSessionContractImplementor session, Object collection) { return new PersistentSet( session, (java.util.Set) collection ); diff --git a/hibernate-core/src/main/java/org/hibernate/type/SortedMapType.java b/hibernate-core/src/main/java/org/hibernate/type/SortedMapType.java index 04b6876bcc..30cb30fada 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/SortedMapType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/SortedMapType.java @@ -12,6 +12,7 @@ import java.util.TreeMap; import org.hibernate.collection.spi.PersistentSortedMap; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.metamodel.CollectionClassification; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.type.spi.TypeConfiguration; @@ -26,14 +27,19 @@ public class SortedMapType extends MapType { } @Override - public PersistentCollection instantiate(SharedSessionContractImplementor session, CollectionPersister persister, Object key) { - return new PersistentSortedMap( session, comparator ); + public CollectionClassification getCollectionClassification() { + return CollectionClassification.SORTED_MAP; } public Class getReturnedClass() { return java.util.SortedMap.class; } + @Override + public PersistentCollection instantiate(SharedSessionContractImplementor session, CollectionPersister persister, Object key) { + return new PersistentSortedMap( session, comparator ); + } + @SuppressWarnings( {"unchecked"}) public Object instantiate(int anticipatedSize) { return new TreeMap(comparator); diff --git a/hibernate-core/src/main/java/org/hibernate/type/SortedSetType.java b/hibernate-core/src/main/java/org/hibernate/type/SortedSetType.java index 5705c3fc22..1f54bc3beb 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/SortedSetType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/SortedSetType.java @@ -12,6 +12,7 @@ import java.util.TreeSet; import org.hibernate.collection.spi.PersistentSortedSet; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.metamodel.CollectionClassification; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.type.spi.TypeConfiguration; @@ -25,14 +26,19 @@ public class SortedSetType extends SetType { } @Override - public PersistentCollection instantiate(SharedSessionContractImplementor session, CollectionPersister persister, Object key) { - return new PersistentSortedSet( session, comparator ); + public CollectionClassification getCollectionClassification() { + return CollectionClassification.SORTED_SET; } public Class getReturnedClass() { return java.util.SortedSet.class; } + @Override + public PersistentCollection instantiate(SharedSessionContractImplementor session, CollectionPersister persister, Object key) { + return new PersistentSortedSet( session, comparator ); + } + @SuppressWarnings( {"unchecked"}) public Object instantiate(int anticipatedSize) { return new TreeSet(comparator); diff --git a/hibernate-core/src/main/java/org/hibernate/usertype/UserCollectionType.java b/hibernate-core/src/main/java/org/hibernate/usertype/UserCollectionType.java index 167f94ff6a..b54fc5343d 100644 --- a/hibernate-core/src/main/java/org/hibernate/usertype/UserCollectionType.java +++ b/hibernate-core/src/main/java/org/hibernate/usertype/UserCollectionType.java @@ -12,15 +12,27 @@ import java.util.Map; import org.hibernate.HibernateException; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.metamodel.CollectionClassification; import org.hibernate.persister.collection.CollectionPersister; /** * A custom type for mapping user-written classes that implement {@code PersistentCollection} * - * @author Gavin King * @see PersistentCollection + * + * @author Gavin King + * @author Steve Ebersole */ public interface UserCollectionType { + /** + * The classification mapped by this custom type + */ + CollectionClassification getClassification(); + + /** + * The Java type that this type maps. + */ + Class getCollectionClass(); /** * Instantiate an uninitialized instance of the collection wrapper diff --git a/hibernate-core/src/main/java/org/hibernate/usertype/UserTypeLegacyBridge.java b/hibernate-core/src/main/java/org/hibernate/usertype/UserTypeLegacyBridge.java index bb008484f8..2d5660acc5 100644 --- a/hibernate-core/src/main/java/org/hibernate/usertype/UserTypeLegacyBridge.java +++ b/hibernate-core/src/main/java/org/hibernate/usertype/UserTypeLegacyBridge.java @@ -10,6 +10,7 @@ import java.util.Properties; import java.util.function.BiConsumer; import org.hibernate.MappingException; +import org.hibernate.annotations.Type; import org.hibernate.type.BasicType; import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfigurationAware; @@ -18,7 +19,7 @@ import org.hibernate.type.spi.TypeConfigurationAware; * Convenience UserType implementation to mimic the legacy `@Type` annotation * which based on the {@code hbm.xml} mapping's String-based type support * - * @see org.hibernate.annotations.CustomType + * @see Type */ public class UserTypeLegacyBridge extends BaseUserTypeSupport implements ParameterizedType, TypeConfigurationAware { public static final String TYPE_NAME_PARAM_KEY = "hbm-type-name"; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/basic/CollectionAsBasicTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/basic/CollectionAsBasicTest.java index 3565e69954..fda690346c 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/basic/CollectionAsBasicTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/basic/CollectionAsBasicTest.java @@ -9,7 +9,7 @@ package org.hibernate.orm.test.annotations.basic; import java.sql.Types; import java.util.Set; -import org.hibernate.annotations.CustomType; +import org.hibernate.annotations.Type; import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistry; @@ -49,7 +49,7 @@ public class CollectionAsBasicTest { public Integer id; public String name; @Basic - @CustomType( DelimitedStringsJavaTypeDescriptor.class ) + @Type( DelimitedStringsJavaTypeDescriptor.class ) Set tags; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/generics/Gene.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/generics/Gene.java index 02fed48b36..8b1fe1e8e9 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/generics/Gene.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/generics/Gene.java @@ -6,7 +6,7 @@ */ package org.hibernate.orm.test.annotations.generics; -import org.hibernate.annotations.CustomType; +import org.hibernate.annotations.Type; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; @@ -22,7 +22,7 @@ public class Gene { private Integer id; private STE state; - @CustomType( StateType.class ) + @Type( StateType.class ) public STE getState() { return state; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/type/dynamicparameterized/Entity1.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/type/dynamicparameterized/Entity1.java index 20d92d130d..ad5791adce 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/type/dynamicparameterized/Entity1.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/type/dynamicparameterized/Entity1.java @@ -23,7 +23,7 @@ */ package org.hibernate.orm.test.annotations.type.dynamicparameterized; -import org.hibernate.annotations.CustomType; +import org.hibernate.annotations.Type; import org.hibernate.annotations.Parameter; import jakarta.persistence.Access; @@ -41,26 +41,26 @@ import jakarta.persistence.Table; public class Entity1 extends AbstractEntity { @Column(name = "PROP1") - @CustomType( MyStringType.class ) + @Type( MyStringType.class ) String entity1_Prop1; @Column(name = "PROP2") - @CustomType( MyStringType.class ) + @Type( MyStringType.class ) String entity1_Prop2; @Column(name = "PROP3") - @CustomType( value = MyStringType.class, parameters = @Parameter(name = "suffix", value = "foo")) + @Type( value = MyStringType.class, parameters = @Parameter(name = "suffix", value = "foo")) String entity1_Prop3; @Column(name = "PROP4") - @CustomType( value = MyStringType.class, parameters = @Parameter(name = "suffix", value = "bar")) + @Type( value = MyStringType.class, parameters = @Parameter(name = "suffix", value = "bar")) String entity1_Prop4; @Column(name = "PROP5") - @CustomType( MyStringType.class ) + @Type( MyStringType.class ) String entity1_Prop5; @Column(name = "PROP6") - @CustomType( MyStringType.class ) + @Type( MyStringType.class ) String entity1_Prop6; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/type/dynamicparameterized/Entity2.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/type/dynamicparameterized/Entity2.java index 7251b89bf9..6c074e0b05 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/type/dynamicparameterized/Entity2.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/type/dynamicparameterized/Entity2.java @@ -23,7 +23,7 @@ */ package org.hibernate.orm.test.annotations.type.dynamicparameterized; -import org.hibernate.annotations.CustomType; +import org.hibernate.annotations.Type; import org.hibernate.annotations.Parameter; import jakarta.persistence.Access; @@ -41,26 +41,26 @@ import jakarta.persistence.Table; public class Entity2 extends AbstractEntity { @Column(name = "PROP1") - @CustomType( MyStringType.class ) + @Type( MyStringType.class ) String entity2_Prop1; @Column(name = "PROP2") - @CustomType( MyStringType.class ) + @Type( MyStringType.class ) String entity2_Prop2; @Column(name = "PROP3") - @CustomType( MyStringType.class ) + @Type( MyStringType.class ) String entity2_Prop3; @Column(name = "PROP4") - @CustomType( MyStringType.class ) + @Type( MyStringType.class ) String entity2_Prop4; @Column(name = "PROP5") - @CustomType( value = MyStringType.class, parameters = @Parameter(name = "suffix", value = "blah")) + @Type( value = MyStringType.class, parameters = @Parameter(name = "suffix", value = "blah")) String entity2_Prop5; @Column(name = "PROP6") - @CustomType( value = MyStringType.class, parameters = @Parameter(name = "suffix", value = "yeah")) + @Type( value = MyStringType.class, parameters = @Parameter(name = "suffix", value = "yeah")) String entity2_Prop6; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/cache/LazyInCacheTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/cache/LazyInCacheTest.java index 20cec9ef95..dc69c38624 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/cache/LazyInCacheTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/cache/LazyInCacheTest.java @@ -7,14 +7,12 @@ package org.hibernate.orm.test.bytecode.enhancement.lazy.cache; import java.nio.charset.Charset; -import java.sql.Types; import java.util.ArrayList; import java.util.List; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.annotations.CustomType; -import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.annotations.Type; import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Configuration; import org.hibernate.usertype.UserTypeLegacyBridge; @@ -97,7 +95,7 @@ public class LazyInCacheTest extends BaseCoreFunctionalTestCase { List tags = new ArrayList<>(); @Basic( fetch = FetchType.LAZY ) - @CustomType( BinaryCustomType.class ) + @Type( BinaryCustomType.class ) // @JdbcTypeCode(Types.LONGVARBINARY) byte[] data; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/cfg/annotations/CollectionBinderTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/cfg/annotations/CollectionBinderTest.java index baed49604e..d2546e4fc3 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/cfg/annotations/CollectionBinderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/cfg/annotations/CollectionBinderTest.java @@ -6,10 +6,6 @@ */ package org.hibernate.orm.test.cfg.annotations; -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - import java.sql.SQLException; import java.util.HashMap; import java.util.Map; @@ -22,15 +18,20 @@ import org.hibernate.cfg.AnnotatedJoinColumn; import org.hibernate.cfg.InheritanceState; import org.hibernate.cfg.PropertyHolder; import org.hibernate.cfg.annotations.CollectionBinder; -import org.hibernate.collection.internal.StandardBagSemantics; import org.hibernate.mapping.Collection; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Table; + import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseUnitTestCase; import org.junit.Test; + import org.mockito.Mockito; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + /** * Test for HHH-10106 * @@ -56,7 +57,7 @@ public class CollectionBinderTest extends BaseUnitTestCase { String expectMessage = "Association [abc] for entity [CollectionBinderTest] references unmapped class [List]"; try { - new CollectionBinder( (t) -> StandardBagSemantics.INSTANCE, false, buildingContext ) { + new CollectionBinder( null, false, buildingContext ) { { final PropertyHolder propertyHolder = Mockito.mock(PropertyHolder.class); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/UserTypeComparableIdTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/UserTypeComparableIdTest.java index 49e98b8211..2e3b939935 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/UserTypeComparableIdTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/UserTypeComparableIdTest.java @@ -14,7 +14,7 @@ import java.sql.Types; import java.util.Comparator; import org.hibernate.HibernateException; -import org.hibernate.annotations.CustomType; +import org.hibernate.annotations.Type; import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.usertype.UserType; @@ -71,7 +71,7 @@ public class UserTypeComparableIdTest { public static class SomeEntity { @Id - @CustomType( CustomIdType.class ) + @Type( CustomIdType.class ) @Column(name = "id") private CustomId customId; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/UserTypeNonComparableIdTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/UserTypeNonComparableIdTest.java index 66064000de..2564840eeb 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/UserTypeNonComparableIdTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/UserTypeNonComparableIdTest.java @@ -18,7 +18,7 @@ import jakarta.persistence.Id; import jakarta.persistence.Table; import org.hibernate.HibernateException; -import org.hibernate.annotations.CustomType; +import org.hibernate.annotations.Type; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.usertype.UserType; @@ -63,7 +63,7 @@ public class UserTypeNonComparableIdTest { public static class SomeEntity { @Id - @CustomType( CustomIdType.class ) + @Type( CustomIdType.class ) @Column(name = "id") private CustomId customId; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/QueryParametersValidationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/QueryParametersValidationTest.java index 806e7c2e54..52f5450ab2 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/QueryParametersValidationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/QueryParametersValidationTest.java @@ -17,7 +17,7 @@ import java.util.Objects; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; -import org.hibernate.annotations.CustomType; +import org.hibernate.annotations.Type; import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; @@ -122,7 +122,7 @@ public class QueryParametersValidationTest extends BaseEntityManagerFunctionalTe @GeneratedValue(strategy = GenerationType.AUTO) private Long id; - @CustomType( QueryParametersValidationTest.BooleanUserType.class ) + @Type( QueryParametersValidationTest.BooleanUserType.class ) private boolean active; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/TypedValueParametersTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/TypedValueParametersTest.java index 8c1c2a53e9..22e8519adc 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/TypedValueParametersTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/TypedValueParametersTest.java @@ -15,6 +15,7 @@ import java.util.Arrays; import java.util.List; import org.hibernate.HibernateException; +import org.hibernate.annotations.Type; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.query.TypedParameterValue; @@ -114,7 +115,7 @@ public class TypedValueParametersTest { @Id private int id; - @org.hibernate.annotations.CustomType( TagUserType.class ) + @Type( TagUserType.class ) @Column(name = "tags") private List tags = new ArrayList<>(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/ImplicitListAsBagSemanticsTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/ImplicitListAsBagSemanticsTests.java index fa22423c76..a4a984d42c 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/ImplicitListAsBagSemanticsTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/ImplicitListAsBagSemanticsTests.java @@ -9,11 +9,9 @@ package org.hibernate.orm.test.mapping.collections; import java.util.Collection; import java.util.List; -import org.hibernate.annotations.CollectionClassificationType; import org.hibernate.cfg.AvailableSettings; import org.hibernate.mapping.Bag; import org.hibernate.mapping.Property; -import org.hibernate.metamodel.CollectionClassification; import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.DomainModelScope; @@ -26,6 +24,7 @@ import jakarta.persistence.Basic; import jakarta.persistence.ElementCollection; import jakarta.persistence.Entity; import jakarta.persistence.Id; +import jakarta.persistence.OrderColumn; import jakarta.persistence.Table; import static org.assertj.core.api.Assertions.assertThat; @@ -82,11 +81,11 @@ public class ImplicitListAsBagSemanticsTests { private Collection implicitBag; @ElementCollection - @CollectionClassificationType( CollectionClassification.BAG ) + @org.hibernate.annotations.Bag private List explicitBag; @ElementCollection - @CollectionClassificationType( CollectionClassification.LIST ) + @OrderColumn( name = "explicit_list_position" ) private List explicitList; private AnEntity() { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/ImplicitListAsListSemanticsTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/ImplicitListAsListSemanticsTests.java index c6fdc2a961..6153d84eb1 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/ImplicitListAsListSemanticsTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/ImplicitListAsListSemanticsTests.java @@ -6,12 +6,9 @@ */ package org.hibernate.orm.test.mapping.collections; -import java.lang.annotation.Annotation; import java.util.Collection; import java.util.List; -import org.hibernate.annotations.CollectionClassificationType; -import org.hibernate.cfg.AvailableSettings; import org.hibernate.mapping.Bag; import org.hibernate.mapping.Property; import org.hibernate.metamodel.CollectionClassification; @@ -19,7 +16,6 @@ import org.hibernate.metamodel.CollectionClassification; import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.DomainModelScope; import org.hibernate.testing.orm.junit.ServiceRegistry; -import org.hibernate.testing.orm.junit.Setting; import org.hibernate.testing.orm.junit.SettingProvider; import org.junit.jupiter.api.Test; @@ -27,6 +23,7 @@ import jakarta.persistence.Basic; import jakarta.persistence.ElementCollection; import jakarta.persistence.Entity; import jakarta.persistence.Id; +import jakarta.persistence.OrderColumn; import jakarta.persistence.Table; import static org.assertj.core.api.Assertions.assertThat; @@ -75,11 +72,11 @@ public class ImplicitListAsListSemanticsTests { private Collection implicitBag; @ElementCollection - @CollectionClassificationType( CollectionClassification.BAG ) + @org.hibernate.annotations.Bag private List explicitBag; @ElementCollection - @CollectionClassificationType( CollectionClassification.LIST ) + @OrderColumn( name = "explicit_list_position" ) private List explicitList; private AnEntity() { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/ImplicitListDefaultSemanticsTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/ImplicitListDefaultSemanticsTests.java index c2bb7e1de3..671b1288ca 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/ImplicitListDefaultSemanticsTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/ImplicitListDefaultSemanticsTests.java @@ -9,11 +9,9 @@ package org.hibernate.orm.test.mapping.collections; import java.util.Collection; import java.util.List; -import org.hibernate.annotations.CollectionClassificationType; import org.hibernate.cfg.AvailableSettings; import org.hibernate.mapping.Bag; import org.hibernate.mapping.Property; -import org.hibernate.metamodel.CollectionClassification; import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.DomainModelScope; @@ -23,6 +21,7 @@ import jakarta.persistence.Basic; import jakarta.persistence.ElementCollection; import jakarta.persistence.Entity; import jakarta.persistence.Id; +import jakarta.persistence.OrderColumn; import jakarta.persistence.Table; import static org.assertj.core.api.Assertions.assertThat; @@ -69,11 +68,11 @@ public class ImplicitListDefaultSemanticsTests { private Collection implicitBag; @ElementCollection - @CollectionClassificationType( CollectionClassification.BAG ) + @org.hibernate.annotations.Bag private List explicitBag; @ElementCollection - @CollectionClassificationType( CollectionClassification.LIST ) + @OrderColumn( name = "explicit_list_position" ) private List explicitList; private AnEntity() { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/classification/bag/BagTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/classification/bag/BagTests.java index 8683e2dca9..39da3634e1 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/classification/bag/BagTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/classification/bag/BagTests.java @@ -20,7 +20,8 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Steve Ebersole */ @DomainModel( annotatedClasses = { - EntityWithBagAsCollection.class + EntityWithBagAsCollection.class, + EntityWithBagAsList.class } ) public class BagTests { @Test @@ -32,4 +33,14 @@ public class BagTests { assertThat( namesMapping.getCollectionSemantics().getCollectionClassification() ).isEqualTo( CollectionClassification.BAG ); } ); } + + @Test + public void verifyListMarkedAsBag(DomainModelScope scope) { + scope.withHierarchy( EntityWithBagAsList.class, (entityDescriptor) -> { + final Property names = entityDescriptor.getProperty( "names" ); + final Collection namesMapping = (Collection) names.getValue(); + + assertThat( namesMapping.getCollectionSemantics().getCollectionClassification() ).isEqualTo( CollectionClassification.BAG ); + } ); + } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/classification/bag/EntityWithBagAsList.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/classification/bag/EntityWithBagAsList.java index 92ebf3aa6e..0efd586d23 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/classification/bag/EntityWithBagAsList.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/classification/bag/EntityWithBagAsList.java @@ -6,11 +6,9 @@ */ package org.hibernate.orm.test.mapping.collections.classification.bag; -import java.util.Collection; import java.util.List; -import org.hibernate.annotations.CollectionClassificationType; -import org.hibernate.metamodel.CollectionClassification; +import org.hibernate.annotations.Bag; import org.hibernate.orm.test.mapping.collections.classification.Name; import jakarta.persistence.Basic; @@ -18,8 +16,6 @@ import jakarta.persistence.ElementCollection; import jakarta.persistence.Entity; import jakarta.persistence.Id; -import static org.hibernate.metamodel.CollectionClassification.BAG; - /** * @author Steve Ebersole */ @@ -36,7 +32,7 @@ public class EntityWithBagAsList { //tag::collections-bag-list-ex[] @ElementCollection - @CollectionClassificationType( BAG ) + @Bag private List names; //end::collections-bag-list-ex[] diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/classification/explicit/EntityWithExplicitSetClassification.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/classification/explicit/EntityWithExplicitSetClassification.java deleted file mode 100644 index 5e16af587f..0000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/classification/explicit/EntityWithExplicitSetClassification.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ -package org.hibernate.orm.test.mapping.collections.classification.explicit; - -import java.util.Collection; - -import org.hibernate.annotations.CollectionClassificationType; -import org.hibernate.orm.test.mapping.collections.classification.Name; - -import jakarta.persistence.Basic; -import jakarta.persistence.ElementCollection; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; - -import static org.hibernate.metamodel.CollectionClassification.SET; - -/** - * @author Steve Ebersole - */ -//tag::collections-bag-set-ex[] -@Entity -public class EntityWithExplicitSetClassification { - // ... -//end::collections-bag-set-ex[] - - @Id - private Integer id; - @Basic - private String name; - - //tag::collections-bag-set-ex[] - @ElementCollection - @CollectionClassificationType(SET) - private Collection names; - //end::collections-bag-set-ex[] - - private EntityWithExplicitSetClassification() { - // for Hibernate use - } - - public EntityWithExplicitSetClassification(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; - } -//tag::collections-bag-set-ex[] -} -//end::collections-bag-set-ex[] diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/Email.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/Email.java similarity index 84% rename from hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/Email.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/Email.java index 6e0d8f52ea..398a97f5dc 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/Email.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/Email.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.orm.test.mapping.type.collection.custom.basic; +package org.hibernate.orm.test.mapping.collections.custom.basic; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/IMyList.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/IMyList.java similarity index 53% rename from hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/IMyList.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/IMyList.java index 465f83e1e7..023a078847 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/IMyList.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/IMyList.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.orm.test.mapping.type.collection.custom.basic; +package org.hibernate.orm.test.mapping.collections.custom.basic; import java.util.List; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/MyList.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/MyList.java similarity index 73% rename from hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/MyList.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/MyList.java index 73bb82e94f..b2727daf3f 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/MyList.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/MyList.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.orm.test.mapping.type.collection.custom.basic; +package org.hibernate.orm.test.mapping.collections.custom.basic; import java.util.ArrayList; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/MyListType.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/MyListType.java similarity index 81% rename from hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/MyListType.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/MyListType.java index 10f53c8d44..dfc3a358f2 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/MyListType.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/MyListType.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.orm.test.mapping.type.collection.custom.basic; +package org.hibernate.orm.test.mapping.collections.custom.basic; import java.util.Iterator; import java.util.Map; @@ -12,6 +12,7 @@ import java.util.Map; import org.hibernate.HibernateException; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.metamodel.CollectionClassification; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.usertype.UserCollectionType; @@ -19,6 +20,16 @@ public class MyListType implements UserCollectionType { static int lastInstantiationRequest = -2; + @Override + public CollectionClassification getClassification() { + return CollectionClassification.LIST; + } + + @Override + public Class getCollectionClass() { + return IMyList.class; + } + @Override public PersistentCollection instantiate(SharedSessionContractImplementor session, CollectionPersister persister) throws HibernateException { return new PersistentMyList( session ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/PersistentMyList.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/PersistentMyList.java similarity index 75% rename from hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/PersistentMyList.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/PersistentMyList.java index f8490a0108..d9f691e336 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/PersistentMyList.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/PersistentMyList.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.orm.test.mapping.type.collection.custom.basic; +package org.hibernate.orm.test.mapping.collections.custom.basic; import org.hibernate.collection.spi.PersistentList; import org.hibernate.engine.spi.SharedSessionContractImplementor; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/User.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/User.java similarity index 89% rename from hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/User.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/User.java index 9c759bea0d..6fd22f9e85 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/User.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/User.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.orm.test.mapping.type.collection.custom.basic; +package org.hibernate.orm.test.mapping.collections.custom.basic; import java.util.List; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/UserCollectionTypeAnnotationsVariantTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/UserCollectionTypeAnnotationsVariantTest.java similarity index 67% rename from hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/UserCollectionTypeAnnotationsVariantTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/UserCollectionTypeAnnotationsVariantTest.java index ce54dd05b1..8fd6c6a168 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/UserCollectionTypeAnnotationsVariantTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/UserCollectionTypeAnnotationsVariantTest.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.orm.test.mapping.type.collection.custom.basic; +package org.hibernate.orm.test.mapping.collections.custom.basic; /** * @author Steve Ebersole diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/UserCollectionTypeHbmVariantTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/UserCollectionTypeHbmVariantTest.java similarity index 55% rename from hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/UserCollectionTypeHbmVariantTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/UserCollectionTypeHbmVariantTest.java index a0d096e5bb..4641791e54 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/UserCollectionTypeHbmVariantTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/UserCollectionTypeHbmVariantTest.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.orm.test.mapping.type.collection.custom.basic; +package org.hibernate.orm.test.mapping.collections.custom.basic; /** * @author Steve Ebersole @@ -17,6 +17,6 @@ public class UserCollectionTypeHbmVariantTest extends UserCollectionTypeTest { @Override public String[] getMappings() { - return new String[] { "/org/hibernate/orm/test/mapping/type/collection/custom/basic/UserPermissions.hbm.xml" }; + return new String[] { "/org/hibernate/orm/test/mapping/collections/custom/basic/UserPermissions.hbm.xml" }; } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/UserCollectionTypeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/UserCollectionTypeTest.java similarity index 90% rename from hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/UserCollectionTypeTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/UserCollectionTypeTest.java index 40bd2173be..5e8ec613d3 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/UserCollectionTypeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/UserCollectionTypeTest.java @@ -1,10 +1,10 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -package org.hibernate.orm.test.mapping.type.collection.custom.basic; +package org.hibernate.orm.test.mapping.collections.custom.basic; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/UserPermissions.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/UserPermissions.hbm.xml similarity index 72% rename from hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/UserPermissions.hbm.xml rename to hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/UserPermissions.hbm.xml index 02e3ab823a..d225834939 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/collection/custom/basic/UserPermissions.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/collections/custom/basic/UserPermissions.hbm.xml @@ -2,8 +2,8 @@ - + - +