From 61d178ef1bb5d30d81051afc38b94a66d49357b0 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Wed, 1 Dec 2021 18:16:29 -0600 Subject: [PATCH] HHH-14885 - New composite user-type `@EmbeddableInstantiatorRegistration` --- .../chapters/domain/embeddables.adoc | 14 ++++ .../annotations/EmbeddableInstantiator.java | 2 +- .../EmbeddableInstantiatorRegistration.java | 29 +++++++ .../EmbeddableInstantiatorRegistrations.java | 24 ++++++ .../InFlightMetadataCollectorImpl.java | 21 +++++ .../boot/spi/InFlightMetadataCollector.java | 4 + .../org/hibernate/cfg/AnnotationBinder.java | 47 ++++++++++- .../cfg/annotations/CollectionBinder.java | 14 +++- .../registered/InstantiationTests.java | 44 ++++++++++ .../instantiator/registered/Name.java | 31 +++++++ .../registered/NameInstantiator.java | 36 +++++++++ .../instantiator/registered/Person.java | 80 +++++++++++++++++++ .../instantiator/registered/package-info.java | 11 +++ 13 files changed, 351 insertions(+), 6 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/annotations/EmbeddableInstantiatorRegistration.java create mode 100644 hibernate-core/src/main/java/org/hibernate/annotations/EmbeddableInstantiatorRegistrations.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/embeddable/strategy/instantiator/registered/InstantiationTests.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/embeddable/strategy/instantiator/registered/Name.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/embeddable/strategy/instantiator/registered/NameInstantiator.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/embeddable/strategy/instantiator/registered/Person.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/embeddable/strategy/instantiator/registered/package-info.java diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/embeddables.adoc b/documentation/src/main/asciidoc/userguide/chapters/domain/embeddables.adoc index 16c8543d02..4e0f7be90c 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/embeddables.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/embeddables.adoc @@ -288,6 +288,20 @@ include::{instantiatorTestDir}/embeddable/Person.java[tags=embeddable-instantiat ==== +Additionally, instantiators can be registered: + +[[embeddable-instantiator-registration-ex]] +.`@EmbeddableInstantiatorRegistration` +==== +[source, JAVA, indent=0] +---- +include::{instantiatorTestDir}/registered/Name.java[tags=embeddable-instantiator-registration] +include::{instantiatorTestDir}/registered/Person.java[tags=embeddable-instantiator-registration] +---- +==== + + + [[embeddable-multiple-namingstrategy]] ==== Embeddables and ImplicitNamingStrategy diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/EmbeddableInstantiator.java b/hibernate-core/src/main/java/org/hibernate/annotations/EmbeddableInstantiator.java index bdcbd4f756..7ac76651ec 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/EmbeddableInstantiator.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/EmbeddableInstantiator.java @@ -16,7 +16,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; /** - * Allows supplying a custom instantiator implementation + * Specifies a custom instantiator implementation */ @Target( {TYPE, FIELD, METHOD, ANNOTATION_TYPE} ) @Retention( RUNTIME ) diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/EmbeddableInstantiatorRegistration.java b/hibernate-core/src/main/java/org/hibernate/annotations/EmbeddableInstantiatorRegistration.java new file mode 100644 index 0000000000..17c6c387a3 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/annotations/EmbeddableInstantiatorRegistration.java @@ -0,0 +1,29 @@ +/* + * 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 java.lang.annotation.Target; + +import org.hibernate.metamodel.spi.EmbeddableInstantiator; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.PACKAGE; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Registers a custom instantiator implementation + */ +@Target( {TYPE, ANNOTATION_TYPE, PACKAGE} ) +@Retention( RUNTIME ) +@Repeatable( EmbeddableInstantiatorRegistrations.class ) +public @interface EmbeddableInstantiatorRegistration { + Class embeddableClass(); + Class instantiator(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/EmbeddableInstantiatorRegistrations.java b/hibernate-core/src/main/java/org/hibernate/annotations/EmbeddableInstantiatorRegistrations.java new file mode 100644 index 0000000000..6ac8b7fdde --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/annotations/EmbeddableInstantiatorRegistrations.java @@ -0,0 +1,24 @@ +/* + * 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 java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.PACKAGE; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * @author Steve Ebersole + */ +@Target( {TYPE, ANNOTATION_TYPE, PACKAGE} ) +@Retention( RUNTIME ) +public @interface EmbeddableInstantiatorRegistrations { + EmbeddableInstantiatorRegistration[] value(); +} 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 e2304c5101..a7d62dd435 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 @@ -98,6 +98,7 @@ import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.Table; import org.hibernate.mapping.UniqueKey; +import org.hibernate.metamodel.spi.EmbeddableInstantiator; import org.hibernate.query.named.NamedObjectRepository; import org.hibernate.query.sqm.function.SqmFunctionDescriptor; import org.hibernate.type.descriptor.java.JavaType; @@ -399,6 +400,26 @@ public void addJdbcTypeRegistration(int typeCode, JdbcType jdbcType) { getTypeConfiguration().getJdbcTypeDescriptorRegistry().addDescriptor( typeCode, jdbcType ); } + private Map, Class> registeredInstantiators; + + @Override + public void registerEmbeddableInstantiator(Class embeddableType, Class instantiator) { + if ( registeredInstantiators == null ) { + registeredInstantiators = new HashMap<>(); + } + registeredInstantiators.put( embeddableType, instantiator ); + } + + @Override + public Class findRegisteredEmbeddableInstantiator(Class embeddableType) { + if ( registeredInstantiators == null ) { + return null; + } + + return registeredInstantiators.get( embeddableType ); + } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 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 e54c380e40..6cf67021ee 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 @@ -49,6 +49,7 @@ import org.hibernate.mapping.MappedSuperclass; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Table; +import org.hibernate.metamodel.spi.EmbeddableInstantiator; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.jdbc.JdbcType; @@ -319,6 +320,9 @@ void addTableNameBinding( void addJavaTypeRegistration(Class javaType, JavaType jtd); void addJdbcTypeRegistration(int typeCode, JdbcType jdbcType); + void registerEmbeddableInstantiator(Class embeddableType, Class instantiator); + Class findRegisteredEmbeddableInstantiator(Class embeddableType); + interface DelayedPropertyReferenceHandler extends Serializable { void process(InFlightMetadataCollector metadataCollector); } 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 f65a71ee8c..f84cc97978 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java @@ -33,6 +33,8 @@ import org.hibernate.annotations.Comment; import org.hibernate.annotations.DiscriminatorFormula; import org.hibernate.annotations.DiscriminatorOptions; +import org.hibernate.annotations.EmbeddableInstantiatorRegistration; +import org.hibernate.annotations.EmbeddableInstantiatorRegistrations; import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchProfile; import org.hibernate.annotations.FetchProfiles; @@ -350,6 +352,7 @@ public static void bindPackage(ClassLoaderService cls, String packageName, Metad } handleTypeDescriptorRegistrations( pckg, context ); + bindEmbeddableInstantiatorRegistrations( pckg, context ); bindGenericGenerators( pckg, context ); bindQueries( pckg, context ); @@ -782,6 +785,7 @@ else if ( InheritanceType.SINGLE_TABLE.equals( inheritanceState.getType() ) ) { // try to find class level generators HashMap classGenerators = buildGenerators( clazzToProcess, context ); handleTypeDescriptorRegistrations( clazzToProcess, context ); + bindEmbeddableInstantiatorRegistrations( clazzToProcess, context ); // check properties final InheritanceState.ElementsToProcess elementsToProcess = inheritanceState.getElementsToProcess(); @@ -910,6 +914,36 @@ private static void handleJavaTypeDescriptorRegistration( context.getMetadataCollector().addJavaTypeRegistration( annotation.javaType(), jtd ); } + private static void bindEmbeddableInstantiatorRegistrations(XAnnotatedElement annotatedElement, MetadataBuildingContext context) { + final ManagedBeanRegistry managedBeanRegistry = context.getBootstrapContext() + .getServiceRegistry() + .getService( ManagedBeanRegistry.class ); + + final EmbeddableInstantiatorRegistration instantiatorReg = annotatedElement.getAnnotation( EmbeddableInstantiatorRegistration.class ); + if ( instantiatorReg != null ) { + handleEmbeddableInstantiatorRegistration( context, managedBeanRegistry, instantiatorReg ); + } + else { + final EmbeddableInstantiatorRegistrations annotation = annotatedElement.getAnnotation( EmbeddableInstantiatorRegistrations.class ); + if ( annotation != null ) { + final EmbeddableInstantiatorRegistration[] registrations = annotation.value(); + for ( int i = 0; i < registrations.length; i++ ) { + handleEmbeddableInstantiatorRegistration( context, managedBeanRegistry, registrations[i] ); + } + } + } + } + + private static void handleEmbeddableInstantiatorRegistration( + MetadataBuildingContext context, + ManagedBeanRegistry managedBeanRegistry, + EmbeddableInstantiatorRegistration annotation) { + context.getMetadataCollector().registerEmbeddableInstantiator( + annotation.embeddableClass(), + annotation.instantiator() + ); + } + /** * Process all discriminator-related metadata per rules for "single table" inheritance */ @@ -2309,7 +2343,7 @@ else if ( !isId || !entityBinder.isIgnoreIdAnnotations() ) { } final AccessType propertyAccessor = entityBinder.getPropertyAccessor( property ); - final Class customInstantiatorImpl = determineCustomInstantiator( property, returnedClass ); + final Class customInstantiatorImpl = determineCustomInstantiator( property, returnedClass, context ); propertyBinder = bindComponent( inferredData, @@ -2457,7 +2491,10 @@ else if ( !isId || !entityBinder.isIgnoreIdAnnotations() ) { } } - private static Class determineCustomInstantiator(XProperty property, XClass returnedClass) { + private static Class determineCustomInstantiator( + XProperty property, + XClass returnedClass, + MetadataBuildingContext context) { if ( property.isAnnotationPresent( EmbeddedId.class ) ) { // we don't allow custom instantiators for composite ids return null; @@ -2473,6 +2510,11 @@ private static Class determineCustomInstantiat return classAnnotation.value(); } + final Class embeddableClass = context.getBootstrapContext().getReflectionManager().toClass( returnedClass ); + if ( embeddableClass != null ) { + return context.getMetadataCollector().findRegisteredEmbeddableInstantiator( embeddableClass ); + } + return null; } @@ -2912,6 +2954,7 @@ public static Component fillComponent( buildingContext.getMetadataCollector().addSecondPass( secondPass ); handleTypeDescriptorRegistrations( property, buildingContext ); + bindEmbeddableInstantiatorRegistrations( property, buildingContext ); } else { Map localGenerators = new HashMap<>( buildGenerators( property, buildingContext ) ); 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 c6c9f502e7..e1af9133b1 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 @@ -1610,7 +1610,7 @@ else if ( owner.getIdentifierMapper() != null && owner.getIdentifierMapper().get false, false, true, - resolveCustomInstantiator( property, elementClass ), + resolveCustomInstantiator( property, elementClass, buildingContext ), buildingContext, inheritanceStatePerClass ); @@ -1672,17 +1672,25 @@ else if ( owner.getIdentifierMapper() != null && owner.getIdentifierMapper().get } - private Class resolveCustomInstantiator(XProperty property, XClass embeddableClass) { + private Class resolveCustomInstantiator( + XProperty property, + XClass propertyClass, + MetadataBuildingContext context) { final org.hibernate.annotations.EmbeddableInstantiator propertyAnnotation = property.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class ); if ( propertyAnnotation != null ) { return propertyAnnotation.value(); } - final org.hibernate.annotations.EmbeddableInstantiator classAnnotation = embeddableClass.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class ); + final org.hibernate.annotations.EmbeddableInstantiator classAnnotation = propertyClass.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class ); if ( classAnnotation != null ) { return classAnnotation.value(); } + final Class embeddableClass = context.getBootstrapContext().getReflectionManager().toClass( propertyClass ); + if ( embeddableClass != null ) { + return context.getMetadataCollector().findRegisteredEmbeddableInstantiator( embeddableClass ); + } + return null; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/embeddable/strategy/instantiator/registered/InstantiationTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/embeddable/strategy/instantiator/registered/InstantiationTests.java new file mode 100644 index 0000000000..8c967c467a --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/embeddable/strategy/instantiator/registered/InstantiationTests.java @@ -0,0 +1,44 @@ +/* + * 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.embeddable.strategy.instantiator.registered; + +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Steve Ebersole + */ +@DomainModel( annotatedClasses = { Person.class, Name.class } ) +@SessionFactory +public class InstantiationTests { + @Test + public void basicTest(SessionFactoryScope scope) { + scope.inTransaction( (session) -> { + final Person mick = new Person( 1, new Name( "Mick", "Jagger" ) ); + session.persist( mick ); + + final Person john = new Person( 2, new Name( "John", "Doe" ) ); + john.addAlias( new Name( "Jon", "Doe" ) ); + session.persist( john ); + } ); + scope.inTransaction( (session) -> { + final Person mick = session.createQuery( "from Person where id = 1", Person.class ).uniqueResult(); + assertThat( mick.getName().getFirstName() ).isEqualTo( "Mick" ); + } ); + scope.inTransaction( (session) -> { + final Person john = session.createQuery( "from Person p join fetch p.aliases where p.id = 2", Person.class ).uniqueResult(); + assertThat( john.getName().getFirstName() ).isEqualTo( "John" ); + assertThat( john.getAliases() ).hasSize( 1 ); + final Name alias = john.getAliases().iterator().next(); + assertThat( alias.getFirstName() ).isEqualTo( "Jon" ); + } ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/embeddable/strategy/instantiator/registered/Name.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/embeddable/strategy/instantiator/registered/Name.java new file mode 100644 index 0000000000..23e5b8b99d --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/embeddable/strategy/instantiator/registered/Name.java @@ -0,0 +1,31 @@ +/* + * 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.embeddable.strategy.instantiator.registered; + +//tag::embeddable-instantiator-registration[] +public class Name { + private final String first; + private final String last; + + private Name() { + throw new UnsupportedOperationException(); + } + + public Name(String first, String last) { + this.first = first; + this.last = last; + } + + public String getFirstName() { + return first; + } + + public String getLastName() { + return last; + } +} +//end::embeddable-instantiator-registration[] \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/embeddable/strategy/instantiator/registered/NameInstantiator.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/embeddable/strategy/instantiator/registered/NameInstantiator.java new file mode 100644 index 0000000000..c3bc64f815 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/embeddable/strategy/instantiator/registered/NameInstantiator.java @@ -0,0 +1,36 @@ +/* + * 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.embeddable.strategy.instantiator.registered; + +import java.util.function.Supplier; + +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.metamodel.spi.EmbeddableInstantiator; + +/** + * @author Steve Ebersole + */ +public class NameInstantiator implements EmbeddableInstantiator { + @Override + public Object instantiate(Supplier valuesAccess, SessionFactoryImplementor sessionFactory) { + final Object[] values = valuesAccess.get(); + // alphabetical + final String first = (String) values[0]; + final String last = (String) values[1]; + return new Name( first, last ); + } + + @Override + public boolean isInstance(Object object, SessionFactoryImplementor sessionFactory) { + return object instanceof Name; + } + + @Override + public boolean isSameClass(Object object, SessionFactoryImplementor sessionFactory) { + return object.getClass().equals( Name.class ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/embeddable/strategy/instantiator/registered/Person.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/embeddable/strategy/instantiator/registered/Person.java new file mode 100644 index 0000000000..2a26d9dc0c --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/embeddable/strategy/instantiator/registered/Person.java @@ -0,0 +1,80 @@ +/* + * 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.embeddable.strategy.instantiator.registered; /** + * @author Steve Ebersole + */ + +import java.util.HashSet; +import java.util.Set; + +import org.hibernate.annotations.EmbeddableInstantiatorRegistration; + +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + + +//tag::embeddable-instantiator-registration[] +@Entity(name = "Person") +@Table(name = "persons") +@EmbeddableInstantiatorRegistration( embeddableClass = Name.class, instantiator = NameInstantiator.class ) +public class Person { + @Id + public Integer id; + @Embedded + public Name name; + @ElementCollection + @Embedded + public Set aliases; + + //end::embeddable-instantiator-registration[] + + private Person() { + // for Hibernate use + } + + public Person(Integer id, Name name) { + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + + public Name getName() { + return name; + } + + public void setName(Name name) { + this.name = name; + } + + public void setId(Integer id) { + this.id = id; + } + + public Set getAliases() { + return aliases; + } + + public void setAliases(Set aliases) { + this.aliases = aliases; + } + + public void addAlias(Name alias) { + if ( aliases == null ) { + aliases = new HashSet<>(); + } + aliases.add( alias ); + } + +//tag::embeddable-instantiator-registration[] +} +//end::embeddable-instantiator-registration[] \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/embeddable/strategy/instantiator/registered/package-info.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/embeddable/strategy/instantiator/registered/package-info.java new file mode 100644 index 0000000000..cce4deb234 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/embeddable/strategy/instantiator/registered/package-info.java @@ -0,0 +1,11 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ + +/** + * Tests for custom {@link org.hibernate.metamodel.spi.EmbeddableInstantiator} usage + */ +package org.hibernate.orm.test.mapping.embeddable.strategy.instantiator.registered; \ No newline at end of file