diff --git a/hibernate-core/hibernate-core.gradle b/hibernate-core/hibernate-core.gradle index 62bc2f56a1..203b1668ab 100644 --- a/hibernate-core/hibernate-core.gradle +++ b/hibernate-core/hibernate-core.gradle @@ -124,10 +124,15 @@ xjc { xjcBindingFile = file( 'src/main/xjb/hbm-mapping-bindings.xjb' ) xjcExtensions += ['inheritance', 'simplify'] } +// orm { +// xsdFile = file( 'src/main/resources/org/hibernate/jpa/orm_2_2.xsd' ) +// xjcBindingFile = file( 'src/main/xjb/mapping-bindings.xjb' ) +// xjcExtensions += ['inheritance'] +// } mapping { - xsdFile = file( 'src/main/resources/org/hibernate/jpa/orm_2_2.xsd' ) + xsdFile = file( 'src/main/resources/org/hibernate/xsd/mapping/mapping-3.1.0.xsd' ) xjcBindingFile = file( 'src/main/xjb/mapping-bindings.xjb' ) - xjcExtensions += ['inheritance'] + xjcExtensions += ['inheritance', 'simplify'] } } } diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/OnDeleteAction.java b/hibernate-core/src/main/java/org/hibernate/annotations/OnDeleteAction.java index 6d2955343b..ec8ab1a8b7 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/OnDeleteAction.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/OnDeleteAction.java @@ -15,9 +15,45 @@ public enum OnDeleteAction { /** * Take no action. The default. */ - NO_ACTION, + NO_ACTION( "no-action" ), /** * Use cascade delete capabilities of the database foreign-key. */ - CASCADE + CASCADE( "cascade" ); + + private final String alternativeName; + + OnDeleteAction(String alternativeName) { + this.alternativeName = alternativeName; + } + + public String getAlternativeName() { + return alternativeName; + } + + public static OnDeleteAction fromExternalForm(Object value) { + if ( value == null ) { + return null; + } + + if ( value instanceof OnDeleteAction ) { + return (OnDeleteAction) value; + } + + final String valueString = value.toString(); + try { + return valueOf( valueString ); + } + catch (IllegalArgumentException e) { + // the name did not match the enum value name... + } + + for ( OnDeleteAction checkAction : values() ) { + if ( checkAction.alternativeName.equalsIgnoreCase( valueString ) ) { + return checkAction; + } + } + + return null; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/OptimisticLockType.java b/hibernate-core/src/main/java/org/hibernate/annotations/OptimisticLockType.java index 731a090321..bbdd747643 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/OptimisticLockType.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/OptimisticLockType.java @@ -9,6 +9,8 @@ package org.hibernate.annotations; /** * Possible optimistic locking strategies. * + * @see OptimisticLocking + * * @author Emmanuel Bernard */ public enum OptimisticLockType { diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/PolymorphismType.java b/hibernate-core/src/main/java/org/hibernate/annotations/PolymorphismType.java index 1fdc0f08f3..98845ff7f5 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/PolymorphismType.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/PolymorphismType.java @@ -6,9 +6,13 @@ */ package org.hibernate.annotations; +import java.util.Locale; + /** * Type of available polymorphism for a particular entity. * + * @see Polymorphism + * * @author Emmanuel Bernard */ public enum PolymorphismType { @@ -19,5 +23,26 @@ public enum PolymorphismType { /** * This entity is retrieved only if explicitly asked. */ - EXPLICIT + EXPLICIT; + + public static PolymorphismType fromExternalValue(Object externalValue) { + if ( externalValue != null ) { + if ( externalValue instanceof PolymorphismType ) { + return (PolymorphismType) externalValue; + } + + final String externalValueStr = externalValue.toString(); + for ( PolymorphismType checkType : values() ) { + if ( checkType.name().equalsIgnoreCase( externalValueStr ) ) { + return checkType; + } + } + } + + return null; + } + + public String getExternalForm() { + return name().toLowerCase( Locale.ROOT ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/MetadataSources.java b/hibernate-core/src/main/java/org/hibernate/boot/MetadataSources.java index 0df16a5768..aaf1eef24d 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/MetadataSources.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/MetadataSources.java @@ -37,8 +37,6 @@ import org.hibernate.internal.CoreMessageLogger; import org.hibernate.service.ServiceRegistry; import org.hibernate.type.SerializationException; -import org.w3c.dom.Document; - /** * Entry point for working with sources of O/R mapping metadata, either * in the form of annotated classes, or as XML mapping documents. @@ -64,9 +62,8 @@ public class MetadataSources implements Serializable { private final ServiceRegistry serviceRegistry; private final ClassLoaderService classLoaderService; - private final boolean disableXmlMappingBinders; - private XmlMappingBinderAccess xmlMappingBinderAccess; + private final XmlMappingBinderAccess xmlMappingBinderAccess; private List> xmlBindings; private LinkedHashSet> annotatedClasses; @@ -88,8 +85,17 @@ public class MetadataSources implements Serializable { * @param serviceRegistry The service registry to use. */ public MetadataSources(ServiceRegistry serviceRegistry) { + this( serviceRegistry, new XmlMappingBinderAccess( serviceRegistry ) ); + } + + /** + * Create a new instance using the given {@link ServiceRegistry}. + * + * @param serviceRegistry The service registry to use. + */ + public MetadataSources(ServiceRegistry serviceRegistry, XmlMappingBinderAccess xmlMappingBinderAccess) { // service registry really should be either BootstrapServiceRegistry or StandardServiceRegistry type... - if ( ! isExpectedServiceRegistryType( serviceRegistry ) ) { + if ( !isExpectedServiceRegistryType( serviceRegistry ) ) { if ( LOG.isDebugEnabled() ) { LOG.debugf( "Unexpected ServiceRegistry type [%s] encountered during building of MetadataSources; may cause " + @@ -100,7 +106,7 @@ public class MetadataSources implements Serializable { } this.serviceRegistry = serviceRegistry; this.classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); - this.disableXmlMappingBinders = false; + this.xmlMappingBinderAccess = xmlMappingBinderAccess; } /** @@ -110,7 +116,9 @@ public class MetadataSources implements Serializable { Objects.requireNonNull( serviceRegistry ); this.serviceRegistry = serviceRegistry; this.classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); - this.disableXmlMappingBinders = disableXmlMappingBinders; + this.xmlMappingBinderAccess = disableXmlMappingBinders + ? null + : new XmlMappingBinderAccess( serviceRegistry ); } protected static boolean isExpectedServiceRegistryType(ServiceRegistry serviceRegistry) { @@ -119,12 +127,6 @@ public class MetadataSources implements Serializable { } public XmlMappingBinderAccess getXmlMappingBinderAccess() { - if ( disableXmlMappingBinders ) { - return null; - } - if ( xmlMappingBinderAccess == null ) { - xmlMappingBinderAccess = new XmlMappingBinderAccess( serviceRegistry ); - } return xmlMappingBinderAccess; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/ResourceLocator.java b/hibernate-core/src/main/java/org/hibernate/boot/ResourceLocator.java new file mode 100644 index 0000000000..75e24cec8f --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/ResourceLocator.java @@ -0,0 +1,27 @@ +/* + * 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.boot; + +import java.net.URL; + +/** + * Abstraction for locating class-path resources + * + * @author Steve Ebersole + */ +@FunctionalInterface +public interface ResourceLocator { + + /** + * Locate the named resource + * + * @param resourceName The resource name to locate + * + * @return The located URL, or {@code null} if no match found + */ + URL locateResource(String resourceName); +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/ResourceStreamLocator.java b/hibernate-core/src/main/java/org/hibernate/boot/ResourceStreamLocator.java new file mode 100644 index 0000000000..86abdf2a69 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/ResourceStreamLocator.java @@ -0,0 +1,27 @@ +/* + * 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.boot; + +import java.io.InputStream; + +/** + * Abstraction for locating class-path resources + * + * @author Steve Ebersole + */ +@FunctionalInterface +public interface ResourceStreamLocator { + + /** + * Locate the named resource + * + * @param resourceName The resource name to locate + * + * @return The located resource's InputStream, or {@code null} if no match found + */ + InputStream locateResourceStream(String resourceName); +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SimpleResourceLocator.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SimpleResourceLocator.java new file mode 100644 index 0000000000..299c4d5b7c --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SimpleResourceLocator.java @@ -0,0 +1,28 @@ +/* + * 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.boot.internal; + +import java.net.URL; + +import org.hibernate.boot.ResourceLocator; + +/** + * Simple ResourceLocator impl using its own ClassLoader to locate the resource + * + * @author Steve Ebersole + */ +public class SimpleResourceLocator implements ResourceLocator { + /** + * Singleton access + */ + public static final SimpleResourceLocator INSTANCE = new SimpleResourceLocator(); + + @Override + public URL locateResource(String resourceName) { + return getClass().getClassLoader().getResource( resourceName ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/StandardResourceLocator.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/StandardResourceLocator.java new file mode 100644 index 0000000000..f3f9388729 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/StandardResourceLocator.java @@ -0,0 +1,30 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. + */ +package org.hibernate.boot.internal; + +import java.net.URL; + +import org.hibernate.boot.ResourceLocator; +import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; + +/** + * Standard implementation of ResourceLocator delegating to the ClassLoaderService + * + * @author Steve Ebersole + */ +public class StandardResourceLocator implements ResourceLocator { + private final ClassLoaderService classLoaderService; + + public StandardResourceLocator(ClassLoaderService classLoaderService) { + this.classLoaderService = classLoaderService; + } + + @Override + public URL locateResource(String resourceName) { + return classLoaderService.locateResource( resourceName ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/ColumnAndFormulaSource.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/ColumnAndFormulaSource.java new file mode 100644 index 0000000000..a744bc7db7 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/ColumnAndFormulaSource.java @@ -0,0 +1,23 @@ +/* + * 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.boot.jaxb.hbm.transform; + +import java.io.Serializable; +import java.util.List; + +/** + * @author Steve Ebersole + */ +interface ColumnAndFormulaSource { + String getColumnAttribute(); + + String getFormulaAttribute(); + + List getColumnOrFormula(); + + SourceColumnAdapter wrap(Serializable column); +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/ColumnAndFormulaTarget.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/ColumnAndFormulaTarget.java new file mode 100644 index 0000000000..2a494f5c45 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/ColumnAndFormulaTarget.java @@ -0,0 +1,18 @@ +/* + * 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.boot.jaxb.hbm.transform; + +/** + * @author Steve Ebersole + */ +interface ColumnAndFormulaTarget { + TargetColumnAdapter makeColumnAdapter(ColumnDefaults columnDefaults); + + void addColumn(TargetColumnAdapter column); + + void addFormula(String formula); +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/ColumnDefaults.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/ColumnDefaults.java new file mode 100644 index 0000000000..5aaab35108 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/ColumnDefaults.java @@ -0,0 +1,26 @@ +/* + * 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.boot.jaxb.hbm.transform; + +/** + * @author Steve Ebersole + */ +interface ColumnDefaults { + Boolean isNullable(); + + Integer getLength(); + + Integer getScale(); + + Integer getPrecision(); + + Boolean isUnique(); + + Boolean isInsertable(); + + Boolean isUpdateable(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/ColumnDefaultsBasicImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/ColumnDefaultsBasicImpl.java new file mode 100644 index 0000000000..78041c7056 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/ColumnDefaultsBasicImpl.java @@ -0,0 +1,52 @@ +/* + * 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.boot.jaxb.hbm.transform; + +/** + * @author Steve Ebersole + */ +public class ColumnDefaultsBasicImpl implements ColumnDefaults { + /** + * Singleton access + */ + public static final ColumnDefaultsBasicImpl INSTANCE = new ColumnDefaultsBasicImpl(); + + @Override + public Boolean isNullable() { + return Boolean.TRUE; + } + + @Override + public Integer getLength() { + return null; + } + + @Override + public Integer getScale() { + return null; + } + + @Override + public Integer getPrecision() { + return null; + } + + @Override + public Boolean isUnique() { + return Boolean.FALSE; + } + + @Override + public Boolean isInsertable() { + return Boolean.TRUE; + } + + @Override + public Boolean isUpdateable() { + return Boolean.TRUE; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/ColumnDefaultsInsertableNonUpdateableImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/ColumnDefaultsInsertableNonUpdateableImpl.java new file mode 100644 index 0000000000..92d35fb810 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/ColumnDefaultsInsertableNonUpdateableImpl.java @@ -0,0 +1,52 @@ +/* + * 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.boot.jaxb.hbm.transform; + +/** + * @author Steve Ebersole + */ +class ColumnDefaultsInsertableNonUpdateableImpl implements ColumnDefaults { + /** + * Singleton access + */ + public static final ColumnDefaultsInsertableNonUpdateableImpl INSTANCE = new ColumnDefaultsInsertableNonUpdateableImpl(); + + @Override + public Boolean isNullable() { + return null; + } + + @Override + public Integer getLength() { + return null; + } + + @Override + public Integer getScale() { + return null; + } + + @Override + public Integer getPrecision() { + return null; + } + + @Override + public Boolean isUnique() { + return null; + } + + @Override + public Boolean isInsertable() { + return true; + } + + @Override + public Boolean isUpdateable() { + return false; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/HbmXmlTransformer.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/HbmXmlTransformer.java new file mode 100644 index 0000000000..645b96e072 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/HbmXmlTransformer.java @@ -0,0 +1,2259 @@ +/* + * 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.boot.jaxb.hbm.transform; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +import org.hibernate.annotations.OnDeleteAction; +import org.hibernate.annotations.PolymorphismType; +import org.hibernate.boot.MappingException; +import org.hibernate.boot.jaxb.JaxbLogger; +import org.hibernate.boot.jaxb.Origin; +import org.hibernate.boot.jaxb.hbm.spi.EntityInfo; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmAnyAssociationType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmArrayType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmAuxiliaryDatabaseObjectType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmBasicAttributeType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmCacheInclusionEnum; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmClassRenameType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmColumnType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmCompositeAttributeType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmCompositeIdType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmCompositeKeyBasicAttributeType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmCompositeKeyManyToOneType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmDiscriminatorSubclassEntityType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmDynamicComponentType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmEntityBaseDefinition; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmFetchProfileType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmFetchStyleEnum; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmFetchStyleWithSubselectEnum; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmFilterAliasMappingType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmFilterDefinitionType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmFilterParameterType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmFilterType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmIdBagCollectionType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmIdentifierGeneratorDefinitionType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmIndexType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmJoinedSubclassEntityType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmLazyEnum; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmLazyWithExtraEnum; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmLazyWithNoProxyEnum; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmListIndexType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmListType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmManyToOneType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmMapType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmNamedNativeQueryType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmNamedQueryType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmNativeQueryCollectionLoadReturnType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmNativeQueryJoinReturnType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmNativeQueryPropertyReturnType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmNativeQueryReturnType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmNativeQueryScalarReturnType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmOnDeleteEnum; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmOneToOneType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmOuterJoinEnum; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmPolymorphismEnum; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmPrimitiveArrayType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmPropertiesType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmQueryParamType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmResultSetMappingType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmRootEntityType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmSecondaryTableType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmSetType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmSimpleIdType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmSynchronizeType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmTimestampAttributeType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmTypeDefinitionType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmUnionSubclassEntityType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmVersionAttributeType; +import org.hibernate.boot.jaxb.hbm.spi.PluralAttributeInfo; +import org.hibernate.boot.jaxb.mapping.AttributesContainer; +import org.hibernate.boot.jaxb.mapping.CollectionAttribute; +import org.hibernate.boot.jaxb.mapping.JaxbAttributes; +import org.hibernate.boot.jaxb.mapping.JaxbBasic; +import org.hibernate.boot.jaxb.mapping.JaxbCacheInclusionType; +import org.hibernate.boot.jaxb.mapping.JaxbCaching; +import org.hibernate.boot.jaxb.mapping.JaxbCascadeType; +import org.hibernate.boot.jaxb.mapping.JaxbCollectionTable; +import org.hibernate.boot.jaxb.mapping.JaxbColumn; +import org.hibernate.boot.jaxb.mapping.JaxbColumnResult; +import org.hibernate.boot.jaxb.mapping.JaxbCustomLoader; +import org.hibernate.boot.jaxb.mapping.JaxbCustomSql; +import org.hibernate.boot.jaxb.mapping.JaxbDatabaseObject; +import org.hibernate.boot.jaxb.mapping.JaxbDatabaseObjectScope; +import org.hibernate.boot.jaxb.mapping.JaxbDiscriminatorColumn; +import org.hibernate.boot.jaxb.mapping.JaxbElementCollection; +import org.hibernate.boot.jaxb.mapping.JaxbEmbeddable; +import org.hibernate.boot.jaxb.mapping.JaxbEmbeddableAttributes; +import org.hibernate.boot.jaxb.mapping.JaxbEmbedded; +import org.hibernate.boot.jaxb.mapping.JaxbEmbeddedId; +import org.hibernate.boot.jaxb.mapping.JaxbEmptyType; +import org.hibernate.boot.jaxb.mapping.JaxbEntity; +import org.hibernate.boot.jaxb.mapping.JaxbEntityMappings; +import org.hibernate.boot.jaxb.mapping.JaxbEntityResult; +import org.hibernate.boot.jaxb.mapping.JaxbFetchProfile; +import org.hibernate.boot.jaxb.mapping.JaxbFieldResult; +import org.hibernate.boot.jaxb.mapping.JaxbFilterDef; +import org.hibernate.boot.jaxb.mapping.JaxbForeignKey; +import org.hibernate.boot.jaxb.mapping.JaxbGenericIdGenerator; +import org.hibernate.boot.jaxb.mapping.JaxbHbmAnyDiscriminator; +import org.hibernate.boot.jaxb.mapping.JaxbHbmAnyDiscriminatorValueMapping; +import org.hibernate.boot.jaxb.mapping.JaxbHbmAnyKey; +import org.hibernate.boot.jaxb.mapping.JaxbHbmAnyMapping; +import org.hibernate.boot.jaxb.mapping.JaxbHbmFilter; +import org.hibernate.boot.jaxb.mapping.JaxbHbmManyToAny; +import org.hibernate.boot.jaxb.mapping.JaxbHqlImport; +import org.hibernate.boot.jaxb.mapping.JaxbId; +import org.hibernate.boot.jaxb.mapping.JaxbIdClass; +import org.hibernate.boot.jaxb.mapping.JaxbInheritance; +import org.hibernate.boot.jaxb.mapping.JaxbJoinColumn; +import org.hibernate.boot.jaxb.mapping.JaxbManyToMany; +import org.hibernate.boot.jaxb.mapping.JaxbManyToOne; +import org.hibernate.boot.jaxb.mapping.JaxbMapKeyColumn; +import org.hibernate.boot.jaxb.mapping.JaxbNamedNativeQuery; +import org.hibernate.boot.jaxb.mapping.JaxbNamedQuery; +import org.hibernate.boot.jaxb.mapping.JaxbNaturalId; +import org.hibernate.boot.jaxb.mapping.JaxbOneToMany; +import org.hibernate.boot.jaxb.mapping.JaxbOneToOne; +import org.hibernate.boot.jaxb.mapping.JaxbOrderColumn; +import org.hibernate.boot.jaxb.mapping.JaxbPersistenceUnitMetadata; +import org.hibernate.boot.jaxb.mapping.JaxbPluralFetchMode; +import org.hibernate.boot.jaxb.mapping.JaxbPrimaryKeyJoinColumn; +import org.hibernate.boot.jaxb.mapping.JaxbQueryParamType; +import org.hibernate.boot.jaxb.mapping.JaxbSecondaryTable; +import org.hibernate.boot.jaxb.mapping.JaxbSingularFetchMode; +import org.hibernate.boot.jaxb.mapping.JaxbSqlResultSetMapping; +import org.hibernate.boot.jaxb.mapping.JaxbSynchronizedTable; +import org.hibernate.boot.jaxb.mapping.JaxbTable; +import org.hibernate.boot.jaxb.mapping.JaxbTransient; +import org.hibernate.boot.jaxb.mapping.JaxbVersion; +import org.hibernate.boot.jaxb.mapping.ToOneAttribute; +import org.hibernate.internal.util.StringHelper; + +import org.jboss.logging.Logger; + +import jakarta.persistence.FetchType; +import jakarta.persistence.InheritanceType; +import jakarta.persistence.TemporalType; +import jakarta.xml.bind.JAXBElement; + +import static org.hibernate.internal.util.StringHelper.isNotEmpty; + +/** + * Transforms a JAXB binding of a hbm.xml file into a unified orm.xml representation + * + * @author Steve Ebersole + * @author Brett Meyer + * + * @implNote This transformation happens on the JAXB model level creating + * a {@link JaxbEntityMappings} "copy" of the {@link JaxbHbmHibernateMapping} + * representation + */ +public class HbmXmlTransformer { + private static final Logger log = Logger.getLogger( HbmXmlTransformer.class ); + + /** + * Main entry into hbm.xml transformation + * + * @param hbmXmlMapping The hbm.xml mapping to be transformed + * @param origin The origin of the hbm.xml mapping + * @return The transformed representation + */ + public static JaxbEntityMappings transform(JaxbHbmHibernateMapping hbmXmlMapping, Origin origin, Options options) { + return new HbmXmlTransformer( hbmXmlMapping, origin, options ).doTransform(); + } + + public interface Options { + UnsupportedFeatureHandling unsupportedFeatureHandling(); + } + + private final Origin origin; + private final JaxbHbmHibernateMapping hbmXmlMapping; + private final JaxbEntityMappings ormRoot; + + private final Options options; + + private String defaultHbmAccess; + private String defaultHbmCascade; + private Boolean defaultHbmLazy; + + public HbmXmlTransformer(JaxbHbmHibernateMapping hbmXmlMapping, Origin origin, Options options) { + this.origin = origin; + this.hbmXmlMapping = hbmXmlMapping; + this.options = options; + + this.ormRoot = new JaxbEntityMappings(); + this.ormRoot.setDescription( + "mapping.xml document auto-generated from legacy hbm.xml format via transformation - " + origin.getName() + ); + + } + + private JaxbEntityMappings doTransform() { + final JaxbPersistenceUnitMetadata metadata = new JaxbPersistenceUnitMetadata(); + ormRoot.setPersistenceUnitMetadata( metadata ); + metadata.setXmlMappingMetadataComplete( new JaxbEmptyType() ); + + defaultHbmAccess = hbmXmlMapping.getDefaultAccess(); + defaultHbmCascade = hbmXmlMapping.getDefaultCascade(); + defaultHbmLazy = hbmXmlMapping.isDefaultLazy(); + + ormRoot.setPackage( hbmXmlMapping.getPackage() ); + ormRoot.setSchema( hbmXmlMapping.getSchema() ); + ormRoot.setCatalog( hbmXmlMapping.getCatalog() ); + + transferTypeDefs(); + transferIdentifierGenerators(); + transferFilterDefs(); + transferFetchProfiles(); + transferImports(); + transferResultSetMappings(); + transferNamedQueries(); + transferNamedNativeQueries(); + transferDatabaseObjects(); + transferEntities(); + + return ormRoot; + } + + private void logUnhandledContent(String description) { + log.warnf( + "Transformation of hbm.xml [%s] encountered unsupported content : %s", + origin.toString(), + description + ); + } + + private void transferTypeDefs() { + JaxbLogger.JAXB_LOGGER.tracef( + "Starting transformation of type-def mappings in `{}`", + origin + ); + + for ( JaxbHbmTypeDefinitionType hbmXmlTypeDef : hbmXmlMapping.getTypedef() ) { + JaxbLogger.JAXB_LOGGER.debugf( + "Starting transformation of type-def mapping `{}` in `{}`", + hbmXmlTypeDef.getName(), + origin + ); + + JaxbLogger.JAXB_LOGGER.infof( + "Skipping type-def mapping (`{}` in `{}` as type-defs are not supported in mapping.xml", + hbmXmlTypeDef.getName(), + origin + ); + +// final JaxbHbmTypeDef typeDef = new JaxbHbmTypeDef(); +// ormRoot.getHbmTypeDef().add( typeDef ); +// typeDef.setName( hbmXmlTypeDef.getName() ); +// typeDef.setClazz( hbmXmlTypeDef.getClazz() ); +// +// for ( JaxbHbmConfigParameterType hbmParam : hbmXmlTypeDef.getConfigParameters() ) { +// final JaxbHbmParam param = new JaxbHbmParam(); +// typeDef.getParam().add( param ); +// param.setName( hbmParam.getName() ); +// param.setValue( hbmParam.getValue() ); +// } + } + } + + private void transferIdentifierGenerators() { + JaxbLogger.JAXB_LOGGER.tracef( + "Starting transformation of identifier-generator mappings in `{}`", + origin + ); + + for ( JaxbHbmIdentifierGeneratorDefinitionType hbmGenerator : hbmXmlMapping.getIdentifierGenerator() ) { + JaxbLogger.JAXB_LOGGER.debugf( + "Starting transformation of identifier-generator mapping `{}` in `{}`", + hbmGenerator.getName(), + origin + ); + + final JaxbGenericIdGenerator generatorDef = new JaxbGenericIdGenerator(); + ormRoot.getGenericGenerators().add( generatorDef ); + generatorDef.setName( hbmGenerator.getName() ); + generatorDef.setClazz( hbmGenerator.getClazz() ); + } + } + + @SuppressWarnings("unchecked") + private void transferFilterDefs() { + JaxbLogger.JAXB_LOGGER.tracef( + "Starting transformation of filter-def mappings in `{}`", + origin + ); + + for ( JaxbHbmFilterDefinitionType hbmFilterDef : hbmXmlMapping.getFilterDef() ) { + JaxbLogger.JAXB_LOGGER.debugf( + "Starting transformation of filter-def mapping `{}` in `{}`", + hbmFilterDef.getName(), + origin + ); + + final JaxbFilterDef filterDef = new JaxbFilterDef(); + ormRoot.getFilterDefinitions().add( filterDef ); + filterDef.setName( hbmFilterDef.getName() ); + + boolean foundCondition = false; + for ( Object content : hbmFilterDef.getContent() ) { + if ( content instanceof String ) { + final String condition = ( (String) content ).trim(); + if (! StringHelper.isEmpty( condition )) { + foundCondition = true; + filterDef.setCondition( condition ); + } + } + else { + final JaxbHbmFilterParameterType hbmFilterParam = ( (JAXBElement) content ).getValue(); + final JaxbFilterDef.JaxbFilterParam param = new JaxbFilterDef.JaxbFilterParam(); + filterDef.getFilterParam().add( param ); + param.setName( hbmFilterParam.getParameterName() ); + param.setType( hbmFilterParam.getParameterValueTypeName() ); + } + } + + if ( !foundCondition ) { + filterDef.setCondition( hbmFilterDef.getCondition() ); + } + } + } + + private void transferImports() { + JaxbLogger.JAXB_LOGGER.tracef( + "Starting transformation of import mappings in `{}`", + origin + ); + + for ( JaxbHbmClassRenameType hbmImport : hbmXmlMapping.getImport() ) { + JaxbLogger.JAXB_LOGGER.debugf( + "Starting transformation of import for `{}` -> `{}` in `{}`", + hbmImport.getClazz(), + hbmImport.getRename(), + origin + ); + + final JaxbHqlImport ormImport = new JaxbHqlImport(); + ormRoot.getHqlImports().add( ormImport ); + ormImport.setClazz( hbmImport.getClazz() ); + ormImport.setRename( hbmImport.getRename() ); + } + } + + private void transferResultSetMappings() { + JaxbLogger.JAXB_LOGGER.tracef( + "Starting transformation of resultset mappings in `{}`", + origin + ); + + for ( JaxbHbmResultSetMappingType hbmResultSet : hbmXmlMapping.getResultset() ) { + JaxbLogger.JAXB_LOGGER.debugf( + "Starting transformation of resultset mapping `{}` in `{}`", + hbmResultSet.getName(), + origin + ); + + final String resultMappingName = hbmResultSet.getName(); + + final JaxbSqlResultSetMapping mapping = new JaxbSqlResultSetMapping(); + mapping.setName( resultMappingName ); + mapping.setDescription( "SQL ResultSet mapping - " + resultMappingName ); + + for ( Serializable hbmReturn : hbmResultSet.getValueMappingSources() ) { + if ( hbmReturn instanceof JaxbHbmNativeQueryReturnType ) { + mapping.getEntityResult().add( + transferEntityReturnElement( + resultMappingName, + (JaxbHbmNativeQueryReturnType) hbmReturn + ) + ); + } + else if ( hbmReturn instanceof JaxbHbmNativeQueryScalarReturnType ) { + mapping.getColumnResult().add( + transferScalarReturnElement( + resultMappingName, + (JaxbHbmNativeQueryScalarReturnType) hbmReturn + ) + ); + } + else if ( hbmReturn instanceof JaxbHbmNativeQueryJoinReturnType ) { + logUnhandledContent( + String.format( + "SQL ResultSet mapping [name=%s] contained a element, " + + "which is not supported for transformation", + resultMappingName + ) + ); + } + else if ( hbmReturn instanceof JaxbHbmNativeQueryCollectionLoadReturnType ) { + logUnhandledContent( + String.format( + "SQL ResultSet mapping [name=%s] contained a element, " + + "which is not supported for transformation", + resultMappingName + ) + ); + } + else { + // should never happen thanks to XSD + logUnhandledContent( + String.format( + "SQL ResultSet mapping [name=%s] contained an unexpected element type", + resultMappingName + ) + ); + } + } + + ormRoot.getSqlResultSetMappings().add( mapping ); + } + } + + private JaxbEntityResult transferEntityReturnElement( + String resultMappingName, + JaxbHbmNativeQueryReturnType hbmReturn) { + final JaxbEntityResult entityResult = new JaxbEntityResult(); + entityResult.setEntityClass( getFullyQualifiedClassName( hbmReturn.getClazz() ) ); + + for ( JaxbHbmNativeQueryPropertyReturnType propertyReturn : hbmReturn.getReturnProperty() ) { + final JaxbFieldResult field = new JaxbFieldResult(); + final List columns = new ArrayList<>(); + if ( !StringHelper.isEmpty( propertyReturn.getColumn() ) ) { + columns.add( propertyReturn.getColumn() ); + } + + for ( JaxbHbmNativeQueryPropertyReturnType.JaxbHbmReturnColumn returnColumn : propertyReturn.getReturnColumn() ) { + columns.add( returnColumn.getName() ); + } + + if ( columns.size() > 1 ) { + logUnhandledContent( + String.format( + "SQL ResultSet mapping [name=%s] contained a element " + + "declaring multiple 1 column mapping, which is not supported for transformation;" + + "skipping that return-property mapping", + resultMappingName, + propertyReturn.getName() + ) + ); + continue; + } + + field.setColumn( columns.get( 0 ) ); + field.setName( propertyReturn.getName() ); + entityResult.getFieldResult().add( field ); + } + return entityResult; + } + + private JaxbColumnResult transferScalarReturnElement( + String resultMappingName, + JaxbHbmNativeQueryScalarReturnType hbmReturn) { + final JaxbColumnResult columnResult = new JaxbColumnResult(); + columnResult.setName( hbmReturn.getColumn() ); + columnResult.setClazz( hbmReturn.getType() ); + logUnhandledContent( + String.format( + "SQL ResultSet mapping [name=%s] contained a element; " + + "transforming type->class likely requires manual adjustment", + resultMappingName, + hbmReturn.getColumn() + ) + ); + return columnResult; + } + + private void transferFetchProfiles() { + JaxbLogger.JAXB_LOGGER.tracef( + "Starting transformation of fetch-profile mappings in `{}`", + origin + ); + + for ( JaxbHbmFetchProfileType hbmFetchProfile : hbmXmlMapping.getFetchProfile() ) { + ormRoot.getFetchProfiles().add( transferFetchProfile( hbmFetchProfile ) ); + } + } + + private JaxbFetchProfile transferFetchProfile(JaxbHbmFetchProfileType hbmFetchProfile) { + JaxbLogger.JAXB_LOGGER.debugf( + "Starting transformation of fetch-profile mapping `{}` in `{}`", + hbmFetchProfile.getName(), + origin + ); + + final JaxbFetchProfile fetchProfile = new JaxbFetchProfile(); + fetchProfile.setName( hbmFetchProfile.getName() ); + for ( JaxbHbmFetchProfileType.JaxbHbmFetch hbmFetch : hbmFetchProfile.getFetch() ) { + final JaxbFetchProfile.JaxbFetch fetch = new JaxbFetchProfile.JaxbFetch(); + fetchProfile.getFetch().add( fetch ); + fetch.setEntity( hbmFetch.getEntity() ); + fetch.setAssociation( hbmFetch.getAssociation() ); + fetch.setStyle( hbmFetch.getStyle().value() ); + } + return fetchProfile; + } + + private void transferNamedQueries() { + JaxbLogger.JAXB_LOGGER.tracef( + "Starting transformation of named-query mappings in `{}`", + origin + ); + + for ( JaxbHbmNamedQueryType hbmQuery : hbmXmlMapping.getQuery() ) { + ormRoot.getNamedQueries().add( transferNamedQuery( hbmQuery, hbmQuery.getName() ) ); + } + } + + private JaxbNamedQuery transferNamedQuery(JaxbHbmNamedQueryType hbmQuery, String name) { + JaxbLogger.JAXB_LOGGER.debugf( + "Starting transformation of named-query mapping `{}` in `{}`", + name, + origin + ); + + final JaxbNamedQuery query = new JaxbNamedQuery(); + query.setName( name ); + query.setCacheable( hbmQuery.isCacheable() ); + query.setCacheMode( hbmQuery.getCacheMode() ); + query.setCacheRegion( hbmQuery.getCacheRegion() ); + query.setComment( hbmQuery.getComment() ); + query.setFetchSize( hbmQuery.getFetchSize() ); + query.setFlushMode( hbmQuery.getFlushMode() ); + query.setFetchSize( hbmQuery.getFetchSize() ); + query.setReadOnly( hbmQuery.isReadOnly() ); + query.setTimeout( hbmQuery.getTimeout() ); + + for ( Object content : hbmQuery.getContent() ) { + if ( content instanceof String ) { + String s = (String) content; + s = s.trim(); + query.setQuery( s ); + } + else { + @SuppressWarnings("unchecked") final JAXBElement element = (JAXBElement) content; + final JaxbHbmQueryParamType hbmQueryParam = element.getValue(); + final JaxbQueryParamType queryParam = new JaxbQueryParamType(); + query.getQueryParam().add( queryParam ); + queryParam.setName( hbmQueryParam.getName() ); + queryParam.setType( hbmQueryParam.getType() ); + } + } + + return query; + } + + private void transferNamedNativeQueries() { + JaxbLogger.JAXB_LOGGER.tracef( + "Starting transformation of (named) query mappings in `{}`", + origin + ); + + for ( JaxbHbmNamedNativeQueryType hbmQuery : hbmXmlMapping.getSqlQuery() ) { + ormRoot.getNamedNativeQueries().add( transferNamedNativeQuery( hbmQuery, hbmQuery.getName() ) ); + } + } + + private JaxbNamedNativeQuery transferNamedNativeQuery(JaxbHbmNamedNativeQueryType hbmQuery, String queryName) { + JaxbLogger.JAXB_LOGGER.debugf( + "Starting transformation of (named) query mapping `{}` in `{}`", + queryName, + origin + ); + + final String implicitResultSetMappingName = queryName + "-implicitResultSetMapping"; + + final JaxbNamedNativeQuery query = new JaxbNamedNativeQuery(); + query.setName( queryName ); + query.setCacheable( hbmQuery.isCacheable() ); + query.setCacheMode( hbmQuery.getCacheMode() ); + query.setCacheRegion( hbmQuery.getCacheRegion() ); + query.setComment( hbmQuery.getComment() ); + query.setFetchSize( hbmQuery.getFetchSize() ); + query.setFlushMode( hbmQuery.getFlushMode() ); + query.setFetchSize( hbmQuery.getFetchSize() ); + query.setReadOnly( hbmQuery.isReadOnly() ); + query.setTimeout( hbmQuery.getTimeout() ); + + JaxbSqlResultSetMapping implicitResultSetMapping = null; + + // JaxbQueryElement#content elements can be either the query or parameters + for ( Object content : hbmQuery.getContent() ) { + if ( content instanceof String ) { + String s = (String) content; + s = s.trim(); + query.setQuery( s ); + } + else if ( content instanceof JAXBElement ) { + final Object element = ( (JAXBElement) content ).getValue(); + if ( element instanceof JaxbHbmQueryParamType ) { + final JaxbHbmQueryParamType hbmQueryParam = (JaxbHbmQueryParamType) element; + final JaxbQueryParamType queryParam = new JaxbQueryParamType(); + queryParam.setName( hbmQueryParam.getName() ); + queryParam.setType( hbmQueryParam.getType() ); + query.getQueryParam().add( queryParam ); + } + else if ( element instanceof JaxbHbmNativeQueryScalarReturnType ) { + if ( implicitResultSetMapping == null ) { + implicitResultSetMapping = new JaxbSqlResultSetMapping(); + implicitResultSetMapping.setName( implicitResultSetMappingName ); + implicitResultSetMapping.setDescription( + String.format( + Locale.ROOT, + "ResultSet mapping implicitly created for named native query `%s` during hbm.xml transformation", + queryName + ) + ); + ormRoot.getSqlResultSetMappings().add( implicitResultSetMapping ); + } + implicitResultSetMapping.getColumnResult().add( + transferScalarReturnElement( + implicitResultSetMappingName, + (JaxbHbmNativeQueryScalarReturnType) element + ) + ); + } + else if ( element instanceof JaxbHbmNativeQueryReturnType ) { + if ( implicitResultSetMapping == null ) { + implicitResultSetMapping = new JaxbSqlResultSetMapping(); + implicitResultSetMapping.setName( implicitResultSetMappingName ); + implicitResultSetMapping.setDescription( + String.format( + Locale.ROOT, + "ResultSet mapping implicitly created for named native query `%s` during hbm.xml transformation", + queryName + ) + ); + ormRoot.getSqlResultSetMappings().add( implicitResultSetMapping ); + } + implicitResultSetMapping.getEntityResult().add( + transferEntityReturnElement( + implicitResultSetMappingName, + (JaxbHbmNativeQueryReturnType) element + ) + ); + } + else if ( element instanceof JaxbHbmNativeQueryCollectionLoadReturnType ) { + logUnhandledContent( + String.format( + "Named native query [name=%s] contained a element, " + + "which is not supported for transformation", + queryName + ) + ); + } + else if ( element instanceof JaxbHbmNativeQueryJoinReturnType ) { + logUnhandledContent( + String.format( + "Named native query [name=%s] contained a element, " + + "which is not supported for transformation", + queryName + ) + ); + } + else if ( element instanceof JaxbHbmSynchronizeType ) { + final JaxbHbmSynchronizeType hbmSynchronize = (JaxbHbmSynchronizeType) element; + final JaxbSynchronizedTable synchronize = new JaxbSynchronizedTable(); + synchronize.setTable( hbmSynchronize.getTable() ); + query.getSynchronizations().add( synchronize ); + } + else { + // should never happen thanks to XSD + logUnhandledContent( + String.format( + "Named native query [name=%s] contained an unexpected element type", + queryName + ) + ); + } + } + } + + return query; + } + + private void transferDatabaseObjects() { + JaxbLogger.JAXB_LOGGER.tracef( + "Starting transformation of database-object mappings in `{}`", + origin + ); + + + for ( JaxbHbmAuxiliaryDatabaseObjectType hbmDatabaseObject : hbmXmlMapping.getDatabaseObject() ) { + // NOTE: database-object does not define a name nor a good "identifier" for logging + + final JaxbDatabaseObject databaseObject = new JaxbDatabaseObject(); + ormRoot.getDatabaseObjects().add( databaseObject ); + + databaseObject.setCreate( hbmDatabaseObject.getCreate() ); + databaseObject.setDrop( hbmDatabaseObject.getDrop() ); + + if ( ! hbmDatabaseObject.getDialectScope().isEmpty() ) { + hbmDatabaseObject.getDialectScope().forEach( (hbmScope) -> { + final JaxbDatabaseObjectScope scope = new JaxbDatabaseObjectScope(); + databaseObject.getDialectScopes().add( scope ); + + scope.setName( hbmScope.getName() ); + // hbm.xml does not define min/max versions for its dialect-scope type + } ); + } + } + } + + private void transferEntities() { + // thoughts... + // 1) We only need to transfer the "extends" attribute if the model is dynamic (map mode), + // otherwise it will be discovered via jandex + // 2) ?? Have abstract hbm class mappings become MappedSuperclass mappings ?? + + for ( JaxbHbmRootEntityType hbmClass : hbmXmlMapping.getClazz() ) { + final JaxbEntity entity = new JaxbEntity(); + ormRoot.getEntities().add( entity ); + transferRootEntity( hbmClass, entity ); + } + + for ( JaxbHbmDiscriminatorSubclassEntityType hbmSubclass : hbmXmlMapping.getSubclass() ) { + final JaxbEntity entity = new JaxbEntity(); + ormRoot.getEntities().add( entity ); + + transferDiscriminatorSubclass( hbmSubclass, entity ); + } + + for ( JaxbHbmJoinedSubclassEntityType hbmSubclass : hbmXmlMapping.getJoinedSubclass() ) { + final JaxbEntity entity = new JaxbEntity(); + ormRoot.getEntities().add( entity ); + + transferJoinedSubclass( hbmSubclass, entity ); + } + + for ( JaxbHbmUnionSubclassEntityType hbmSubclass : hbmXmlMapping.getUnionSubclass() ) { + final JaxbEntity entity = new JaxbEntity(); + ormRoot.getEntities().add( entity ); + + transferUnionSubclass( hbmSubclass, entity ); + } + + } + + private void transferRootEntity(JaxbHbmRootEntityType hbmClass, JaxbEntity entity) { + transferBaseEntityInformation( hbmClass, entity ); + + entity.setMutable( hbmClass.isMutable() ); + + entity.setTable( new JaxbTable() ); + entity.getTable().setCatalog( hbmClass.getCatalog() ); + entity.getTable().setSchema( hbmClass.getSchema() ); + entity.getTable().setName( hbmClass.getTable() ); + entity.getTable().setComment( hbmClass.getComment() ); + entity.getTable().setCheck( hbmClass.getCheck() ); + entity.setTableExpression( hbmClass.getSubselect() ); + + for ( JaxbHbmSynchronizeType hbmSync : hbmClass.getSynchronize() ) { + final JaxbSynchronizedTable sync = new JaxbSynchronizedTable(); + sync.setTable( hbmSync.getTable() ); + entity.getSynchronize().add( sync ); + } + + if ( hbmClass.getLoader() != null ) { + entity.setLoader( new JaxbCustomLoader() ); + entity.getLoader().setQueryRef( hbmClass.getLoader().getQueryRef() ); + } + if ( hbmClass.getSqlInsert() != null ) { + entity.setSqlInsert( new JaxbCustomSql() ); + entity.getSqlInsert().setValue( hbmClass.getSqlInsert().getValue() ); + entity.getSqlInsert().setCheck( hbmClass.getSqlInsert().getCheck() ); + entity.getSqlInsert().setValue( hbmClass.getSqlInsert().getValue() ); + } + if ( hbmClass.getSqlUpdate() != null ) { + entity.setSqlUpdate( new JaxbCustomSql() ); + entity.getSqlUpdate().setValue( hbmClass.getSqlUpdate().getValue() ); + entity.getSqlUpdate().setCheck( hbmClass.getSqlUpdate().getCheck() ); + entity.getSqlUpdate().setValue( hbmClass.getSqlUpdate().getValue() ); + } + if ( hbmClass.getSqlDelete() != null ) { + entity.setSqlDelete( new JaxbCustomSql() ); + entity.getSqlDelete().setValue( hbmClass.getSqlDelete().getValue() ); + entity.getSqlDelete().setCheck( hbmClass.getSqlDelete().getCheck() ); + entity.getSqlDelete().setValue( hbmClass.getSqlDelete().getValue() ); + } + entity.setRowid( hbmClass.getRowid() ); + entity.setWhere( hbmClass.getWhere() ); + + if ( !hbmClass.getTuplizer().isEmpty() ) { + if ( options.unsupportedFeatureHandling() == UnsupportedFeatureHandling.ERROR ) { + throw new MappingException( "HBM transformation: Tuplizer not supported", origin ); + } + } + + entity.setOptimisticLock( hbmClass.getOptimisticLock() ); + + transferDiscriminator( hbmClass, entity ); + entity.setDiscriminatorValue( hbmClass.getDiscriminatorValue() ); + entity.setPolymorphism( convert( hbmClass.getPolymorphism() ) ); + + if ( hbmClass.getCache() != null ) { + transferEntityCaching( hbmClass, entity ); + } + + for ( JaxbHbmNamedQueryType hbmQuery : hbmClass.getQuery() ) { + entity.getNamedQuery().add( transferNamedQuery( hbmQuery, entity.getName() + "." + hbmQuery.getName() ) ); + } + + for ( JaxbHbmNamedNativeQueryType hbmQuery : hbmClass.getSqlQuery() ) { + entity.getNamedNativeQuery().add( + transferNamedNativeQuery( + hbmQuery, + entity.getName() + "." + hbmQuery.getName() + ) + ); + } + + for ( JaxbHbmFilterType hbmFilter : hbmClass.getFilter()) { + entity.getFilter().add( convert( hbmFilter ) ); + } + + for ( JaxbHbmFetchProfileType hbmFetchProfile : hbmClass.getFetchProfile() ) { + entity.getFetchProfile().add( transferFetchProfile( hbmFetchProfile ) ); + } + + transferAttributes( hbmClass, entity ); + + for ( JaxbHbmJoinedSubclassEntityType hbmSubclass : hbmClass.getJoinedSubclass() ) { + entity.setInheritance( new JaxbInheritance() ); + entity.getInheritance().setStrategy( InheritanceType.JOINED ); + + final JaxbEntity subclassEntity = new JaxbEntity(); + ormRoot.getEntities().add( subclassEntity ); + transferJoinedSubclass( hbmSubclass, subclassEntity ); + } + + for (JaxbHbmUnionSubclassEntityType hbmSubclass : hbmClass.getUnionSubclass() ) { + entity.setInheritance( new JaxbInheritance() ); + entity.getInheritance().setStrategy( InheritanceType.TABLE_PER_CLASS ); + + final JaxbEntity subclassEntity = new JaxbEntity(); + ormRoot.getEntities().add( subclassEntity ); + transferUnionSubclass( hbmSubclass, subclassEntity ); + } + + for ( JaxbHbmDiscriminatorSubclassEntityType hbmSubclass : hbmClass.getSubclass() ) { + final JaxbEntity subclassEntity = new JaxbEntity(); + ormRoot.getEntities().add( subclassEntity ); + transferDiscriminatorSubclass( hbmSubclass, subclassEntity ); + } + + for ( JaxbHbmNamedQueryType hbmQuery : hbmClass.getQuery() ) { + // Tests implied this was the case... + final String name = hbmClass.getName() + "." + hbmQuery.getName(); + ormRoot.getNamedQueries().add( transferNamedQuery( hbmQuery, name ) ); + } + + for ( JaxbHbmNamedNativeQueryType hbmQuery : hbmClass.getSqlQuery() ) { + // Tests implied this was the case... + final String name = hbmClass.getName() + "." + hbmQuery.getName(); + ormRoot.getNamedNativeQueries().add( transferNamedNativeQuery( hbmQuery, name ) ); + } + } + + private void transferEntityCaching(JaxbHbmRootEntityType hbmClass, JaxbEntity entity) { + entity.setCaching( new JaxbCaching() ); + entity.getCaching().setRegion( hbmClass.getCache().getRegion() ); + entity.getCaching().setAccess( hbmClass.getCache().getUsage() ); + entity.getCaching().setInclude( convert( hbmClass.getCache().getInclude() ) ); + } + + private JaxbCacheInclusionType convert(JaxbHbmCacheInclusionEnum hbmInclusion) { + if ( hbmInclusion == null ) { + return null; + } + + if ( hbmInclusion == JaxbHbmCacheInclusionEnum.NON_LAZY ) { + return JaxbCacheInclusionType.NON_LAZY; + } + + if ( hbmInclusion == JaxbHbmCacheInclusionEnum.ALL ) { + return JaxbCacheInclusionType.ALL; + } + + throw new IllegalArgumentException( "Unrecognized cache-inclusions value : " + hbmInclusion ); + } + + private PolymorphismType convert(JaxbHbmPolymorphismEnum polymorphism) { + if ( polymorphism == null ) { + return null; + } + return polymorphism == JaxbHbmPolymorphismEnum.EXPLICIT ? PolymorphismType.EXPLICIT : PolymorphismType.IMPLICIT; + } + + private static void transferIfSet(Supplier source, Consumer target) { + transferIfSet( source, target, Objects::nonNull ); + } + + private static void transferIfSet(Supplier source, Consumer target, Function valueChecker) { + final T value = source.get(); + if ( valueChecker.apply( value ) ) { + target.accept( value ); + } + } + + private void transferBaseEntityInformation(JaxbHbmEntityBaseDefinition hbmClass, JaxbEntity entity) { + entity.setMetadataComplete( true ); + entity.setName( hbmClass.getEntityName() ); + entity.setClazz( hbmClass.getName() ); + entity.setAbstract( hbmClass.isAbstract() ); + entity.setLazy( hbmClass.isLazy() ); + entity.setProxy( hbmClass.getProxy() ); + + entity.setBatchSize( hbmClass.getBatchSize() ); + + entity.setDynamicInsert( hbmClass.isDynamicInsert() ); + entity.setDynamicUpdate( hbmClass.isDynamicUpdate() ); + entity.setSelectBeforeUpdate( hbmClass.isSelectBeforeUpdate() ); + + if ( hbmClass.getPersister() != null ) { + if ( options.unsupportedFeatureHandling() == UnsupportedFeatureHandling.ERROR ) { + throw new UnsupportedOperationException( + String.format( + Locale.ROOT, + "Transforming mappings not supported for `%s` in `%s`", + entity.getName(), + origin + ) + ); + } + } + } + + private void transferDiscriminatorSubclass(JaxbHbmDiscriminatorSubclassEntityType hbmSubclass, JaxbEntity subclassEntity) { + transferBaseEntityInformation( hbmSubclass, subclassEntity ); + if ( !StringHelper.isEmpty( hbmSubclass.getDiscriminatorValue() ) ) { + subclassEntity.setDiscriminatorValue( hbmSubclass.getDiscriminatorValue() ); + } + transferEntityElementAttributes( hbmSubclass, subclassEntity ); + } + + private void transferJoinedSubclass(JaxbHbmJoinedSubclassEntityType hbmSubclass, JaxbEntity subclassEntity) { + transferBaseEntityInformation( hbmSubclass, subclassEntity ); + transferEntityElementAttributes( hbmSubclass, subclassEntity ); + + subclassEntity.setTable( new JaxbTable() ); + subclassEntity.getTable().setCatalog( hbmSubclass.getCatalog() ); + subclassEntity.getTable().setSchema( hbmSubclass.getSchema() ); + subclassEntity.getTable().setName( hbmSubclass.getTable() ); + subclassEntity.getTable().setComment( hbmSubclass.getComment() ); + subclassEntity.getTable().setCheck( hbmSubclass.getCheck() ); + + if ( hbmSubclass.getKey() != null ) { + final JaxbPrimaryKeyJoinColumn joinColumn = new JaxbPrimaryKeyJoinColumn(); + // TODO: multiple columns? + joinColumn.setName( hbmSubclass.getKey().getColumnAttribute() ); + subclassEntity.getPrimaryKeyJoinColumn().add( joinColumn ); + } + + if ( !hbmSubclass.getJoinedSubclass().isEmpty() ) { + subclassEntity.setInheritance( new JaxbInheritance() ); + subclassEntity.getInheritance().setStrategy( InheritanceType.JOINED ); + for ( JaxbHbmJoinedSubclassEntityType nestedHbmSubclass : hbmSubclass.getJoinedSubclass() ) { + final JaxbEntity nestedSubclassEntity = new JaxbEntity(); + ormRoot.getEntities().add( nestedSubclassEntity ); + transferJoinedSubclass( nestedHbmSubclass, nestedSubclassEntity ); + } + } + } + + private void transferColumnsAndFormulas( + ColumnAndFormulaSource source, + ColumnAndFormulaTarget target, + ColumnDefaults columnDefaults, + String tableName) { + if ( isNotEmpty( source.getFormulaAttribute() ) ) { + target.addFormula( source.getFormulaAttribute() ); + } + else if ( isNotEmpty( source.getColumnAttribute() ) ) { + final TargetColumnAdapter column = target.makeColumnAdapter( columnDefaults ); + column.setName( source.getColumnAttribute() ); + column.setTable( tableName ); + target.addColumn( column ); + } + else { + for ( Serializable columnOrFormula : source.getColumnOrFormula() ) { + if ( columnOrFormula instanceof String ) { + target.addFormula( (String) columnOrFormula ); + } + else { + final JaxbHbmColumnType hbmColumn = (JaxbHbmColumnType) columnOrFormula; + final TargetColumnAdapter column = target.makeColumnAdapter( columnDefaults ); + column.setTable( tableName ); + transferColumn( source.wrap( hbmColumn ), column ); + target.addColumn( column ); + } + } + } + } + + private void transferColumn( + SourceColumnAdapter source, + TargetColumnAdapter target) { + target.setName( source.getName() ); + + target.setNullable( invert( source.isNotNull() ) ); + target.setUnique( source.isUnique() ); + + target.setLength( source.getLength() ); + target.setScale( source.getScale() ); + target.setPrecision( source.getPrecision() ); + + target.setComment( source.getComment() ); + + target.setCheck( source.getCheck() ); + target.setDefault( source.getDefault() ); + + target.setColumnDefinition( source.getSqlType() ); + + target.setRead( source.getRead() ); + target.setWrite( source.getWrite() ); + + } + + private void transferColumn( + SourceColumnAdapter source, + TargetColumnAdapter target, + String tableName, + ColumnDefaults columnDefaults) { + target.setName( source.getName() ); + target.setTable( tableName ); + + target.setNullable( invert( source.isNotNull(), columnDefaults.isNullable() ) ); + + if ( source.getLength() != null ) { + target.setLength( source.getLength() ); + } + else { + target.setLength( columnDefaults.getLength() ); + } + + if ( source.getScale() != null ) { + target.setScale( source.getScale() ); + } + else { + target.setScale( columnDefaults.getScale() ); + } + + if ( source.getPrecision() != null ) { + target.setPrecision( source.getPrecision() ); + } + else { + target.setPrecision( columnDefaults.getPrecision() ); + } + + if ( source.isUnique() != null ) { + target.setUnique( source.isUnique() ); + } + else { + target.setUnique( columnDefaults.isUnique() ); + } + + target.setInsertable( columnDefaults.isInsertable() ); + target.setUpdatable( columnDefaults.isUpdateable() ); + + target.setComment( source.getComment() ); + + target.setCheck( source.getCheck() ); + target.setDefault( source.getDefault() ); + + target.setColumnDefinition( source.getSqlType() ); + + target.setRead( source.getRead() ); + target.setWrite( source.getWrite() ); + } + + private void transferDiscriminator(final JaxbHbmRootEntityType hbmClass, final JaxbEntity entity) { + if ( hbmClass.getDiscriminator() == null ) { + return; + } + + if ( isNotEmpty( hbmClass.getDiscriminator().getColumnAttribute() ) ) { + entity.setDiscriminatorColumn( new JaxbDiscriminatorColumn() ); + entity.getDiscriminatorColumn().setName( hbmClass.getDiscriminator().getColumnAttribute() ); + } + else if ( StringHelper.isEmpty( hbmClass.getDiscriminator().getFormulaAttribute() ) ) { + entity.setDiscriminatorFormula( hbmClass.getDiscriminator().getFormulaAttribute() ); + } + else if ( StringHelper.isEmpty( hbmClass.getDiscriminator().getFormula() ) ) { + entity.setDiscriminatorFormula( hbmClass.getDiscriminator().getFormulaAttribute().trim() ); + } + else { + entity.setDiscriminatorColumn( new JaxbDiscriminatorColumn() ); + entity.getDiscriminatorColumn().setName( hbmClass.getDiscriminator().getColumn().getName() ); + entity.getDiscriminatorColumn().setColumnDefinition( hbmClass.getDiscriminator().getColumn().getSqlType() ); + entity.getDiscriminatorColumn().setLength( hbmClass.getDiscriminator().getColumn().getLength() ); + entity.getDiscriminatorColumn().setForceSelection( hbmClass.getDiscriminator().isForce() ); + } + } + + private void transferAttributes(JaxbHbmRootEntityType source, JaxbEntity target) { + transferEntityElementAttributes( source, target ); + + transferIdentifier( source, target ); + transferNaturalIdentifiers( source, target ); + transferVersion( source, target ); + transferTimestamp( source, target ); + + transferJoins( source, target ); + } + + + private void transferEntityElementAttributes(EntityInfo hbmClass, JaxbEntity entity) { + entity.setAttributes( new JaxbAttributes() ); + transferAttributes( hbmClass.getAttributes(), entity.getAttributes() ); + } + + private void transferAttributes(List hbmAttributeMappings, AttributesContainer attributes) { + for ( Object hbmAttributeMapping : hbmAttributeMappings ) { + if ( hbmAttributeMapping instanceof JaxbHbmBasicAttributeType ) { + final JaxbHbmBasicAttributeType basic = (JaxbHbmBasicAttributeType) hbmAttributeMapping; + attributes.getBasicAttributes().add( convertBasicAttribute( basic ) ); + } + else if ( hbmAttributeMapping instanceof JaxbHbmCompositeAttributeType ) { + final JaxbHbmCompositeAttributeType hbmComponent = (JaxbHbmCompositeAttributeType) hbmAttributeMapping; + ormRoot.getEmbeddables().add( convertEmbeddable( hbmComponent ) ); + attributes.getEmbeddedAttributes().add( convertEmbedded( hbmComponent ) ); + } + else if ( hbmAttributeMapping instanceof JaxbHbmPropertiesType ) { + final JaxbHbmPropertiesType hbmProperties = (JaxbHbmPropertiesType) hbmAttributeMapping; + transferAttributes( hbmProperties.getAttributes(), attributes ); + } + else if ( hbmAttributeMapping instanceof JaxbHbmDynamicComponentType ) { + final String name = ( (JaxbHbmDynamicComponentType) hbmAttributeMapping ).getName(); + logUnhandledContent( + String.format( + Locale.ROOT, + " mappings not supported for transformation [name=%s]", + name + ) + ); + } + else if ( hbmAttributeMapping instanceof JaxbHbmOneToOneType ) { + final JaxbHbmOneToOneType o2o = (JaxbHbmOneToOneType) hbmAttributeMapping; + transformOneToOne( o2o, attributes ); + } + else if ( hbmAttributeMapping instanceof JaxbHbmManyToOneType ) { + final JaxbHbmManyToOneType m2o = (JaxbHbmManyToOneType) hbmAttributeMapping; + attributes.getManyToOneAttributes().add( convertManyToOne( m2o ) ); + } + else if ( hbmAttributeMapping instanceof JaxbHbmAnyAssociationType ) { + final JaxbHbmAnyAssociationType any = (JaxbHbmAnyAssociationType) hbmAttributeMapping; + attributes.getDiscriminatedAssociations().add( convertAnyAttribute( any ) ); + + } + else if ( hbmAttributeMapping instanceof PluralAttributeInfo ) { + final PluralAttributeInfo pluralAttributeInfo = (PluralAttributeInfo) hbmAttributeMapping; + + if ( pluralAttributeInfo.getElement() != null + || pluralAttributeInfo.getCompositeElement() != null ) { + attributes.getElementCollectionAttributes().add( convertElementCollection( pluralAttributeInfo ) ); + } + else if ( pluralAttributeInfo.getOneToMany() != null ) { + attributes.getOneToManyAttributes().add( convertOneToManyCollection( pluralAttributeInfo ) ); + } + else if ( pluralAttributeInfo.getManyToMany() != null ) { + attributes.getManyToManyAttributes().add( convertManyToManyCollection( pluralAttributeInfo ) ); + } + else if ( pluralAttributeInfo.getManyToAny() != null ) { + attributes.getPluralDiscriminatedAssociations() + .add( convertManyToAnyCollection( pluralAttributeInfo ) ); + } + } + } + } + + private JaxbBasic convertBasicAttribute(final JaxbHbmBasicAttributeType hbmProp) { + final JaxbBasic basic = new JaxbBasic(); + transferBasicAttribute( hbmProp, basic ); + return basic; + } + + private void transferBasicAttribute(JaxbHbmBasicAttributeType hbmProp, JaxbBasic basic) { + basic.setName( hbmProp.getName() ); + basic.setOptional( hbmProp.isNotNull() == null || !hbmProp.isNotNull() ); + basic.setFetch( FetchType.EAGER ); + basic.setAttributeAccessor( hbmProp.getAccess() ); + basic.setOptimisticLock( hbmProp.isOptimisticLock() ); + +// if ( isNotEmpty( hbmProp.getTypeAttribute() ) ) { +// basic.setType( new JaxbHbmType() ); +// basic.getType().setName( hbmProp.getTypeAttribute() ); +// } +// else { +// if ( hbmProp.getType() != null ) { +// basic.setType( new JaxbHbmType() ); +// basic.getType().setName( hbmProp.getType().getName() ); +// for ( JaxbHbmConfigParameterType hbmParam : hbmProp.getType().getConfigParameters() ) { +// final JaxbHbmParam param = new JaxbHbmParam(); +// param.setName( hbmParam.getName() ); +// param.setValue( hbmParam.getValue() ); +// basic.getType().getParam().add( param ); +// } +// } +// } + + transferColumnsAndFormulas( + new ColumnAndFormulaSource() { + @Override + public String getColumnAttribute() { + return hbmProp.getColumnAttribute(); + } + + @Override + public String getFormulaAttribute() { + return hbmProp.getFormulaAttribute(); + } + + @Override + public List getColumnOrFormula() { + return hbmProp.getColumnOrFormula(); + } + + @Override + public SourceColumnAdapter wrap(Serializable column) { + return new SourceColumnAdapterJaxbHbmColumnType( (JaxbHbmColumnType) column ); + } + }, + new ColumnAndFormulaTarget() { + @Override + public TargetColumnAdapter makeColumnAdapter(ColumnDefaults columnDefaults) { + return new TargetColumnAdapterJaxbColumn( columnDefaults ); + } + + @Override + public void addColumn(TargetColumnAdapter column) { + basic.setColumn( ( (TargetColumnAdapterJaxbColumn) column ).getTargetColumn() ); + } + + @Override + public void addFormula(String formula) { + basic.setFormula( formula ); + } + }, + new ColumnDefaults() { + @Override + public Boolean isNullable() { + return invert( hbmProp.isNotNull() ); + } + + @Override + public Integer getLength() { + return hbmProp.getLength(); + } + + @Override + public Integer getScale() { + return isNotEmpty( hbmProp.getScale() ) + ? Integer.parseInt( hbmProp.getScale() ) + : null; + } + + @Override + public Integer getPrecision() { + return isNotEmpty( hbmProp.getPrecision() ) + ? Integer.parseInt( hbmProp.getPrecision() ) + : null; + } + + @Override + public Boolean isUnique() { + return hbmProp.isUnique(); + } + + @Override + public Boolean isInsertable() { + return hbmProp.isInsert(); + } + + @Override + public Boolean isUpdateable() { + return hbmProp.isUpdate(); + } + }, + // todo : need to push the table name down into this method to pass along + null + ); + } + + private JaxbEmbeddable convertEmbeddable(JaxbHbmCompositeAttributeType hbmComponent) { + final JaxbEmbeddable embeddable = new JaxbEmbeddable(); + embeddable.setClazz( hbmComponent.getClazz() ); + embeddable.setAttributes( new JaxbEmbeddableAttributes() ); + + transferAttributes( hbmComponent.getAttributes(), embeddable.getAttributes() ); + + return embeddable; + } + + private JaxbEmbedded convertEmbedded(JaxbHbmCompositeAttributeType hbmComponent) { + final JaxbEmbedded embedded = new JaxbEmbedded(); + embedded.setName( hbmComponent.getName() ); + embedded.setAttributeAccessor( hbmComponent.getAccess() ); + return embedded; + } + + private void transformOneToOne(JaxbHbmOneToOneType hbmOneToOne, AttributesContainer attributes) { + if ( !hbmOneToOne.getFormula().isEmpty() || !StringHelper.isEmpty( hbmOneToOne.getFormulaAttribute() ) ) { + if ( options.unsupportedFeatureHandling() == UnsupportedFeatureHandling.ERROR ) { + throw new MappingException( "HBM transformation: Formulas within one-to-ones are not yet supported.", origin ); + } + return; + } + + final JaxbOneToOne oneToOne = new JaxbOneToOne(); + oneToOne.setAttributeAccessor( hbmOneToOne.getAccess() ); + oneToOne.setCascade( convertCascadeType( hbmOneToOne.getCascade() ) ); + oneToOne.setOrphanRemoval( isOrphanRemoval( hbmOneToOne.getCascade() ) ); + oneToOne.setForeignKey( new JaxbForeignKey() ); + oneToOne.getForeignKey().setName( hbmOneToOne.getForeignKey() ); + if (! StringHelper.isEmpty( hbmOneToOne.getPropertyRef() ) ) { + final JaxbJoinColumn joinColumn = new JaxbJoinColumn(); + joinColumn.setReferencedColumnName( hbmOneToOne.getPropertyRef() ); + oneToOne.getJoinColumn().add( joinColumn ); + } + oneToOne.setName( hbmOneToOne.getName() ); + if ( isNotEmpty( hbmOneToOne.getEntityName() ) ) { + oneToOne.setTargetEntity( hbmOneToOne.getEntityName() ); + } + else { + oneToOne.setTargetEntity( hbmOneToOne.getClazz() ); + } + + transferFetchable( hbmOneToOne.getLazy(), hbmOneToOne.getFetch(), hbmOneToOne.getOuterJoin(), hbmOneToOne.isConstrained(), oneToOne ); + + attributes.getOneToOneAttributes().add( oneToOne ); + } + + private JaxbManyToOne convertManyToOne(final JaxbHbmManyToOneType hbmM2O) { + final JaxbManyToOne m2o = new JaxbManyToOne(); + m2o.setAttributeAccessor( hbmM2O.getAccess() ); + m2o.setCascade( convertCascadeType( hbmM2O.getCascade() ) ); + m2o.setForeignKey( new JaxbForeignKey() ); + m2o.getForeignKey().setName( hbmM2O.getForeignKey() ); + + transferColumnsAndFormulas( + new ColumnAndFormulaSource() { + @Override + public String getColumnAttribute() { + return hbmM2O.getColumnAttribute(); + } + + @Override + public String getFormulaAttribute() { + return hbmM2O.getFormulaAttribute(); + } + + @Override + public List getColumnOrFormula() { + return hbmM2O.getColumnOrFormula(); + } + + @Override + public SourceColumnAdapter wrap(Serializable column) { + return new SourceColumnAdapterJaxbHbmColumnType( (JaxbHbmColumnType) column ); + } + }, + new ColumnAndFormulaTarget() { + @Override + public TargetColumnAdapter makeColumnAdapter(ColumnDefaults columnDefaults) { + return new TargetColumnAdapterJaxbJoinColumn( columnDefaults ); + } + + @Override + public void addColumn(TargetColumnAdapter column) { + m2o.getJoinColumn().add( ( (TargetColumnAdapterJaxbJoinColumn) column ).getTargetColumn() ); + } + + @Override + public void addFormula(String formula) { + logUnhandledContent( + " [name=" + hbmM2O.getName() + "] specified formula [" + formula + + "] which is not supported for transformation; skipping" + ); + } + }, + ColumnDefaultsBasicImpl.INSTANCE, + null + ); + + m2o.setName( hbmM2O.getName() ); + m2o.setOptional( hbmM2O.isNotNull() == null || !hbmM2O.isNotNull() ); + if ( isNotEmpty( hbmM2O.getEntityName() ) ) { + m2o.setTargetEntity( hbmM2O.getEntityName() ); + } + else { + m2o.setTargetEntity( hbmM2O.getClazz() ); + } + transferFetchable( hbmM2O.getLazy(), hbmM2O.getFetch(), hbmM2O.getOuterJoin(), null, m2o ); + return m2o; + } + + + private JaxbHbmAnyMapping convertAnyAttribute(JaxbHbmAnyAssociationType source) { + final JaxbHbmAnyMapping target = new JaxbHbmAnyMapping(); + + target.setName( source.getName() ); + target.setAttributeAccessor( source.getAccess() ); + target.setOptimisticLock( source.isOptimisticLock() ); + + // todo : cascade + // todo : discriminator column + // todo : key column + + target.setDiscriminator( new JaxbHbmAnyDiscriminator() ); + source.getMetaValue().forEach( (sourceMapping) -> { + final JaxbHbmAnyDiscriminatorValueMapping mapping = new JaxbHbmAnyDiscriminatorValueMapping(); + mapping.setDiscriminatorValue( sourceMapping.getValue() ); + mapping.setCorrespondingEntityName( sourceMapping.getClazz() ); + target.getDiscriminator().getValueMappings().add( mapping ); + } ); + + target.setKey( new JaxbHbmAnyKey() ); + + return target; + } + + private JaxbElementCollection convertElementCollection(final PluralAttributeInfo source) { + final JaxbElementCollection target = new JaxbElementCollection(); + transferCollectionTable( source, target ); + transferCollectionBasicInfo( source, target ); + + if ( source instanceof JaxbHbmMapType ) { + transferMapKey( (JaxbHbmMapType) source, target ); + } + + if ( source.getElement() != null ) { + transferColumnsAndFormulas( + new ColumnAndFormulaSource() { + @Override + public String getColumnAttribute() { + return source.getElement().getColumnAttribute(); + } + + @Override + public String getFormulaAttribute() { + return source.getElement().getFormulaAttribute(); + } + + @Override + public List getColumnOrFormula() { + return source.getElement().getColumnOrFormula(); + } + + @Override + public SourceColumnAdapter wrap(Serializable column) { + return new SourceColumnAdapterJaxbHbmColumnType( (JaxbHbmColumnType) column ); + } + }, + new ColumnAndFormulaTarget() { + @Override + public TargetColumnAdapter makeColumnAdapter(ColumnDefaults columnDefaults) { + return new TargetColumnAdapterJaxbColumn( columnDefaults ); + } + + @Override + public void addColumn(TargetColumnAdapter column) { + target.setColumn( ( (TargetColumnAdapterJaxbColumn) column ).getTargetColumn() ); + } + + @Override + public void addFormula(String formula) { + target.setFormula( formula ); + } + }, + ColumnDefaultsBasicImpl.INSTANCE, + null + ); + } + else { + target.setTargetClass( source.getCompositeElement().getClazz() ); + + // todo : account for same embeddable used multiple times + final JaxbEmbeddable embeddedable = new JaxbEmbeddable(); + embeddedable.setClazz( source.getCompositeElement().getClazz() ); + embeddedable.setAttributes( new JaxbEmbeddableAttributes() ); + transferAttributes( + source.getCompositeElement().getAttributes(), + embeddedable.getAttributes() + ); + ormRoot.getEmbeddables().add( embeddedable ); + } + + return target; + } + + private void transferCollectionTable( + final PluralAttributeInfo source, + final JaxbElementCollection target) { + target.setCollectionTable( new JaxbCollectionTable() ); + + if ( isNotEmpty( source.getTable() ) ) { + target.getCollectionTable().setName( source.getTable() ); + target.getCollectionTable().setCatalog( source.getCatalog() ); + target.getCollectionTable().setSchema( source.getSchema() ); + } + + transferColumnsAndFormulas( + new ColumnAndFormulaSource() { + @Override + public String getColumnAttribute() { + return source.getKey().getColumnAttribute(); + } + + @Override + public String getFormulaAttribute() { + return null; + } + + @Override + public List getColumnOrFormula() { + return new ArrayList( source.getKey().getColumn() ); + } + + @Override + public SourceColumnAdapter wrap(Serializable column) { + return new SourceColumnAdapterJaxbHbmColumnType( (JaxbHbmColumnType) column ); + } + }, + new ColumnAndFormulaTarget() { + @Override + public TargetColumnAdapter makeColumnAdapter(ColumnDefaults columnDefaults) { + return new TargetColumnAdapterJaxbJoinColumn( columnDefaults ); + } + + @Override + public void addColumn(TargetColumnAdapter column) { + + } + + @Override + public void addFormula(String formula) { + logUnhandledContent( + "formula as part of element-collection key is not supported for transformation; skipping" + ); + } + }, + ColumnDefaultsBasicImpl.INSTANCE, + source.getTable() + + ); + + if ( isNotEmpty( source.getKey().getPropertyRef() ) ) { + logUnhandledContent( + "Foreign-key () for persistent collection (name=" + source.getName() + + ") specified property-ref which is not supported for transformation; " + + "transformed will need manual adjustment of referenced-column-name" + ); + } + } + + + private void transferCollectionBasicInfo(PluralAttributeInfo source, CollectionAttribute target) { + target.setName( source.getName() ); + target.setAttributeAccessor( source.getAccess() ); + target.setFetchMode( convert( source.getFetch() ) ); + + if ( source instanceof JaxbHbmSetType ) { + final JaxbHbmSetType set = (JaxbHbmSetType) source; + target.setSort( set.getSort() ); + target.setOrderBy( set.getOrderBy() ); + } + else if ( source instanceof JaxbHbmMapType ) { + final JaxbHbmMapType map = (JaxbHbmMapType) source; + target.setSort( map.getSort() ); + target.setOrderBy( map.getOrderBy() ); + } + else if ( source instanceof JaxbHbmIdBagCollectionType ) { + // todo : collection-id + } + else if ( source instanceof JaxbHbmListType ) { + transferListIndex( + ( (JaxbHbmListType) source ).getIndex(), + ( (JaxbHbmListType) source ).getListIndex(), + target + ); + } + else if ( source instanceof JaxbHbmArrayType ) { + transferListIndex( + ( (JaxbHbmArrayType) source ).getIndex(), + ( (JaxbHbmArrayType) source ).getListIndex(), + target + ); + } + else if ( source instanceof JaxbHbmPrimitiveArrayType ) { + transferListIndex( + ( (JaxbHbmPrimitiveArrayType) source ).getIndex(), + ( (JaxbHbmPrimitiveArrayType) source ).getListIndex(), + target + ); + } + } + + private void transferListIndex( + JaxbHbmIndexType index, + JaxbHbmListIndexType listIndex, + CollectionAttribute target) { + final JaxbOrderColumn orderColumn = new JaxbOrderColumn(); + target.setOrderColumn( orderColumn ); + + if ( index != null ) { + // todo : base on order-column + if ( isNotEmpty( index.getColumnAttribute() ) ) { + orderColumn.setName( index.getColumnAttribute() ); + } + else if ( index.getColumn().size() == 1 ) { + final JaxbHbmColumnType hbmColumn = index.getColumn().get( 0 ); + orderColumn.setName( hbmColumn.getName() ); + orderColumn.setNullable( invert( hbmColumn.isNotNull() ) ); + orderColumn.setColumnDefinition( hbmColumn.getSqlType() ); + } + } + else if ( listIndex != null ) { + // todo : base on order-column + if ( isNotEmpty( listIndex.getColumnAttribute() ) ) { + orderColumn.setName( listIndex.getColumnAttribute() ); + } + else if ( listIndex.getColumn() != null ) { + orderColumn.setName( listIndex.getColumn().getName() ); + orderColumn.setNullable( invert( listIndex.getColumn().isNotNull() ) ); + orderColumn.setColumnDefinition( listIndex.getColumn().getSqlType() ); + } + } + } + + private void transferMapKey(JaxbHbmMapType source, CollectionAttribute target) { + if ( source.getIndex() != null ) { + final JaxbMapKeyColumn mapKey = new JaxbMapKeyColumn(); + // TODO: multiple columns? + mapKey.setName( source.getIndex().getColumnAttribute() ); + target.setMapKeyColumn( mapKey ); + } + else if ( source.getMapKey() != null ) { + if ( ! StringHelper.isEmpty( source.getMapKey().getFormulaAttribute() ) ) { + if ( options.unsupportedFeatureHandling() == UnsupportedFeatureHandling.ERROR ) { + throw new MappingException( "HBM transformation: Formulas within map keys are not yet supported.", origin ); + } + return; + } + + final JaxbMapKeyColumn mapKey = new JaxbMapKeyColumn(); + mapKey.setName( source.getMapKey().getColumnAttribute() ); + target.setMapKeyColumn( mapKey ); + } + } + + private Boolean invert(Boolean value) { + return invert( value, null ); + } + + private Boolean invert(Boolean value, Boolean defaultValue) { + if ( value == null ) { + return defaultValue; + } + return !value; + } + + private JaxbPluralFetchMode convert(JaxbHbmFetchStyleWithSubselectEnum fetch) { + if ( fetch != null ) { + switch ( fetch ) { + case SELECT: { + return JaxbPluralFetchMode.SELECT; + } + case JOIN: { + return JaxbPluralFetchMode.JOIN; + } + case SUBSELECT: { + return JaxbPluralFetchMode.SUBSELECT; + } + } + } + + return null; + } + + private JaxbOneToMany convertOneToManyCollection(PluralAttributeInfo pluralAttributeInfo) { + throw new MappingException( "OneToMany transformation not yet implemented", origin ); + } + + private JaxbManyToMany convertManyToManyCollection(PluralAttributeInfo pluralAttributeInfo) { + throw new MappingException( "ManyToMany transformation not yet implemented", origin ); + } + + private JaxbHbmManyToAny convertManyToAnyCollection(PluralAttributeInfo pluralAttributeInfo) { + throw new MappingException( "ManyToAny transformation not yet implemented", origin ); + } + + private void transferIdentifier(JaxbHbmRootEntityType source, JaxbEntity target) { + if ( source.getId() != null ) { + target.getAttributes().getId().add( convertSimpleId( source.getId() ) ); + } + else { + final JaxbHbmCompositeIdType hbmCompositeId = source.getCompositeId(); + assert hbmCompositeId != null; + + final boolean isAggregate; + if ( isNotEmpty( hbmCompositeId.getClazz() ) ) { + // we have . + if ( hbmCompositeId.isMapped() ) { + // user explicitly said the class is an "IdClass" + isAggregate = false; + } + else { + isAggregate = true; + } + } + else { + // there was no class specified, can only be non-aggregated + isAggregate = false; + } + + if ( isAggregate ) { + target.getAttributes().setEmbeddedId( new JaxbEmbeddedId() ); + target.getAttributes().getEmbeddedId().setName( hbmCompositeId.getName() ); + target.getAttributes().getEmbeddedId().setAttributeAccessor( hbmCompositeId.getAccess() ); + + final JaxbEmbeddable embeddable = new JaxbEmbeddable(); + embeddable.setClazz( hbmCompositeId.getClazz() ); + embeddable.setAttributes( new JaxbEmbeddableAttributes() ); + for ( Object hbmCompositeAttribute : hbmCompositeId.getKeyPropertyOrKeyManyToOne() ) { + if ( hbmCompositeAttribute instanceof JaxbHbmCompositeKeyBasicAttributeType ) { + final JaxbHbmCompositeKeyBasicAttributeType keyProp = (JaxbHbmCompositeKeyBasicAttributeType) hbmCompositeAttribute; + final JaxbBasic basic = new JaxbBasic(); + basic.setName( keyProp.getName() ); + basic.setAttributeAccessor( keyProp.getAccess() ); + if ( isNotEmpty( keyProp.getColumnAttribute() ) ) { + final JaxbColumn column = new JaxbColumn(); + column.setName( keyProp.getColumnAttribute() ); + basic.setColumn( column ); + } + else { + for ( JaxbHbmColumnType hbmColumn : keyProp.getColumn() ) { + final JaxbColumn column = new JaxbColumn(); + transferColumn( + new SourceColumnAdapterJaxbHbmColumnType( hbmColumn ), + new TargetColumnAdapterJaxbColumn( column, ColumnDefaultsInsertableNonUpdateableImpl.INSTANCE ) + ); + basic.setColumn( column ); + } + } + embeddable.getAttributes().getBasicAttributes().add( basic ); + } + else { + final JaxbHbmCompositeKeyManyToOneType keyManyToOne = (JaxbHbmCompositeKeyManyToOneType) hbmCompositeAttribute; + final JaxbManyToOne manyToOne = transferManyToOneAttribute( keyManyToOne ); + embeddable.getAttributes().getManyToOneAttributes().add( manyToOne ); + } + } + ormRoot.getEmbeddables().add( embeddable ); + } + else { + final JaxbIdClass idClass = new JaxbIdClass(); + idClass.setClazz( hbmCompositeId.getClazz() ); + target.setIdClass( idClass ); + for ( Object hbmCompositeAttribute : hbmCompositeId.getKeyPropertyOrKeyManyToOne() ) { + if ( hbmCompositeAttribute instanceof JaxbHbmCompositeKeyBasicAttributeType ) { + final JaxbHbmCompositeKeyBasicAttributeType keyProp = (JaxbHbmCompositeKeyBasicAttributeType) hbmCompositeAttribute; + final JaxbId id = new JaxbId(); + id.setName( keyProp.getName() ); + id.setAttributeAccessor( keyProp.getAccess() ); + if ( isNotEmpty( keyProp.getColumnAttribute() ) ) { + final JaxbColumn column = new JaxbColumn(); + column.setName( keyProp.getColumnAttribute() ); + id.setColumn( column ); + } + else { + if ( keyProp.getColumn().size() == 1 ) { + id.setColumn( new JaxbColumn() ); + transferColumn( + new SourceColumnAdapterJaxbHbmColumnType( keyProp.getColumn().get( 0 ) ), + new TargetColumnAdapterJaxbColumn( id.getColumn(), ColumnDefaultsInsertableNonUpdateableImpl.INSTANCE ) + ); + } + } + target.getAttributes().getId().add( id ); + } + else { + final JaxbHbmCompositeKeyManyToOneType keyManyToOne = (JaxbHbmCompositeKeyManyToOneType) hbmCompositeAttribute; + final JaxbManyToOne manyToOne = transferManyToOneAttribute( keyManyToOne ); + target.getAttributes().getManyToOneAttributes().add( manyToOne ); + } + } + } + } + } + + + private JaxbId convertSimpleId(JaxbHbmSimpleIdType source) { + final JaxbId target = new JaxbId(); + target.setName( source.getName() ); + target.setAttributeAccessor( source.getAccess() ); + +// // this depends on how we want to model "generic generators" in the mapping xsd. this might +// // mean "inline" like we do in hbm.xml or using separate generator declarations like orm.xml +// if ( source.getGenerator() != null ) { +// final JaxbGenericIdGenerator generator = new JaxbGenericIdGenerator(); +// generator.setStrategy( source.getGenerator().getClazz() ); +// for ( JaxbHbmConfigParameterType param : source.getGenerator().getConfigParameters() ) { +// JaxbHbmParam hbmParam = new JaxbHbmParam(); +// hbmParam.setName( param.getName() ); +// hbmParam.setValue( param.getValue() ); +// generator.getParam().add( hbmParam ); +// } +// target.getGeneratedValue().setGenerator( generator ); +// } + +// if ( isNotEmpty( source.getTypeAttribute() ) ) { +// target.setType( new JaxbHbmType() ); +// target.getType().setName( source.getTypeAttribute() ); +// } +// else { +// if ( source.getType() != null ) { +// target.setType( new JaxbHbmType() ); +// target.getType().setName( source.getType().getName() ); +// for ( JaxbHbmConfigParameterType hbmParam : source.getType().getConfigParameters() ) { +// final JaxbHbmParam param = new JaxbHbmParam(); +// param.setName( hbmParam.getName() ); +// param.setValue( hbmParam.getValue() ); +// target.getType().getParam().add( param ); +// } +// } +// } + + target.setUnsavedValue( source.getUnsavedValue() ); + + if ( isNotEmpty( source.getColumnAttribute() ) ) { + target.setColumn( new JaxbColumn() ); + target.getColumn().setName( source.getColumnAttribute() ); + } + else { + if ( source.getColumn() != null ) { + if ( source.getColumn().size() == 1 ) { + target.setColumn( new JaxbColumn() ); + transferColumn( + new SourceColumnAdapterJaxbHbmColumnType( source.getColumn().get( 0 ) ), + new TargetColumnAdapterJaxbColumn( target.getColumn(), ColumnDefaultsInsertableNonUpdateableImpl.INSTANCE ) + ); + } + } + } + + return target; + } + + + private void transferNaturalIdentifiers(JaxbHbmRootEntityType source, JaxbEntity target) { + if ( source.getNaturalId() == null ) { + return; + } + + final JaxbNaturalId naturalId = new JaxbNaturalId(); + transferAttributes( + source.getNaturalId().getAttributes(), + new AttributesContainer() { + @Override + public List getBasicAttributes() { + return naturalId.getBasic(); + } + + @Override + public List getEmbeddedAttributes() { + return naturalId.getEmbedded(); + } + + @Override + public List getOneToOneAttributes() { + return null; + } + + @Override + public List getManyToOneAttributes() { + return null; + } + + @Override + public List getDiscriminatedAssociations() { + return null; + } + + @Override + public List getElementCollectionAttributes() { + return null; + } + + @Override + public List getOneToManyAttributes() { + return null; + } + + @Override + public List getManyToManyAttributes() { + return null; + } + + @Override + public List getPluralDiscriminatedAssociations() { + return null; + } + + @Override + public List getTransients() { + return null; + } + } + ); + + naturalId.setMutable( source.getNaturalId().isMutable() ); + target.getAttributes().setNaturalId( naturalId ); + } + + private void transferVersion(JaxbHbmRootEntityType source, JaxbEntity target) { + final JaxbHbmVersionAttributeType hbmVersion = source.getVersion(); + if ( hbmVersion != null ) { + final JaxbVersion version = new JaxbVersion(); + version.setName( hbmVersion.getName() ); + if ( isNotEmpty( hbmVersion.getColumnAttribute() ) ) { + version.setColumn( new JaxbColumn() ); + version.getColumn().setName( hbmVersion.getColumnAttribute() ); + } + target.getAttributes().getVersion().add( version ); + } + } + + private void transferTimestamp(JaxbHbmRootEntityType source, JaxbEntity target) { + final JaxbHbmTimestampAttributeType hbmTimestamp = source.getTimestamp(); + if ( hbmTimestamp != null ) { + final JaxbVersion version = new JaxbVersion(); + version.setName( hbmTimestamp.getName() ); + // TODO: multiple columns? + if ( isNotEmpty( hbmTimestamp.getColumnAttribute() ) ) { + version.setColumn( new JaxbColumn() ); + version.getColumn().setName( hbmTimestamp.getColumnAttribute() ); + } + version.setTemporal( TemporalType.TIMESTAMP ); + target.getAttributes().getVersion().add( version ); + } + } + + private void transferJoins(JaxbHbmRootEntityType source, JaxbEntity target) { + for ( JaxbHbmSecondaryTableType hbmJoin : source.getJoin() ) { + if ( !hbmJoin.isInverse() ) { + final JaxbSecondaryTable secondaryTable = new JaxbSecondaryTable(); + secondaryTable.setCatalog( hbmJoin.getCatalog() ); + secondaryTable.setComment( hbmJoin.getComment() ); + secondaryTable.setName( hbmJoin.getTable() ); + secondaryTable.setSchema( hbmJoin.getSchema() ); + secondaryTable.setOptional( hbmJoin.isOptional() ); + if ( hbmJoin.getKey() != null ) { + final JaxbPrimaryKeyJoinColumn joinColumn = new JaxbPrimaryKeyJoinColumn(); + joinColumn.setName( hbmJoin.getKey().getColumnAttribute() ); + secondaryTable.getPrimaryKeyJoinColumn().add( joinColumn ); + } + target.getSecondaryTable().add( secondaryTable ); + } + + for ( Serializable attributeMapping : hbmJoin.getAttributes() ) { + if ( attributeMapping instanceof JaxbHbmBasicAttributeType ) { + final JaxbBasic prop = convertBasicAttribute( (JaxbHbmBasicAttributeType) attributeMapping ); + if ( prop.getColumn() != null ) { + prop.getColumn().setTable( hbmJoin.getTable() ); + } + target.getAttributes().getBasicAttributes().add( prop ); + } + else if ( attributeMapping instanceof JaxbHbmCompositeAttributeType ) { + throw new MappingException( + "transformation of as part of (secondary-table) not yet implemented", + origin + ); + } + else if ( attributeMapping instanceof JaxbHbmManyToOneType ) { + throw new MappingException( + "transformation of as part of (secondary-table) not yet implemented", + origin + ); + } + else if ( attributeMapping instanceof JaxbHbmAnyAssociationType ) { + throw new MappingException( + "transformation of as part of (secondary-table) not yet implemented", + origin + ); + } + else if ( attributeMapping instanceof JaxbHbmDynamicComponentType ) { + logUnhandledContent( + " mappings not supported; skipping" + ); + } + } + } + } + + private JaxbManyToOne transferManyToOneAttribute(JaxbHbmCompositeKeyManyToOneType hbmM2O) { + final JaxbManyToOne m2o = new JaxbManyToOne(); + m2o.setId( true ); + m2o.setName( hbmM2O.getName() ); + m2o.setAttributeAccessor( hbmM2O.getAccess() ); + m2o.setFetch( convert( hbmM2O.getLazy() ) ); + m2o.setForeignKey( new JaxbForeignKey() ); + m2o.getForeignKey().setName( hbmM2O.getForeignKey() ); + if ( !hbmM2O.getColumn().isEmpty() ) { + for ( JaxbHbmColumnType hbmColumn : hbmM2O.getColumn() ) { + final JaxbJoinColumn joinColumn = new JaxbJoinColumn(); + joinColumn.setName( hbmColumn.getName() ); + joinColumn.setNullable( hbmColumn.isNotNull() == null ? null : !hbmColumn.isNotNull() ); + joinColumn.setUnique( hbmColumn.isUnique() ); + m2o.getJoinColumn().add( joinColumn ); + } + } + else { + final JaxbJoinColumn joinColumn = new JaxbJoinColumn(); + if ( StringHelper.isEmpty( hbmM2O.getColumnAttribute() )) { + // AbstractBasicBindingTests seems to imply this was the case + joinColumn.setName( hbmM2O.getName() ); + } + else { + joinColumn.setName( hbmM2O.getColumnAttribute() ); + } + m2o.getJoinColumn().add( joinColumn ); + } + + if ( isNotEmpty( hbmM2O.getEntityName() ) ) { + m2o.setTargetEntity( hbmM2O.getEntityName() ); + } + else { + m2o.setTargetEntity( hbmM2O.getClazz() ); + } + if (hbmM2O.getOnDelete() != null) { + m2o.setOnDelete( convert( hbmM2O.getOnDelete() ) ); + } + return m2o; + } + + private void transferUnionSubclass(JaxbHbmUnionSubclassEntityType hbmSubclass, JaxbEntity subclassEntity) { + if ( !StringHelper.isEmpty( hbmSubclass.getProxy() ) ) { + // TODO + throw new MappingException( "HBM transformation: proxy attributes not yet supported", origin ); + } + transferBaseEntityInformation( hbmSubclass, subclassEntity ); + transferEntityElementAttributes( hbmSubclass, subclassEntity ); + + subclassEntity.setTable( new JaxbTable() ); + subclassEntity.getTable().setCatalog( hbmSubclass.getCatalog() ); + subclassEntity.getTable().setSchema( hbmSubclass.getSchema() ); + subclassEntity.getTable().setName( hbmSubclass.getTable() ); + subclassEntity.getTable().setComment( hbmSubclass.getComment() ); + subclassEntity.getTable().setCheck( hbmSubclass.getCheck() ); + + if ( !hbmSubclass.getUnionSubclass().isEmpty() ) { + subclassEntity.setInheritance( new JaxbInheritance() ); + subclassEntity.getInheritance().setStrategy( InheritanceType.TABLE_PER_CLASS ); + for ( JaxbHbmUnionSubclassEntityType nestedHbmSubclass : hbmSubclass.getUnionSubclass() ) { + final JaxbEntity nestedSubclassEntity = new JaxbEntity(); + ormRoot.getEntities().add( nestedSubclassEntity ); + transferUnionSubclass( nestedHbmSubclass, nestedSubclassEntity ); + } + } + } + + + // ToOne + private void transferFetchable( + JaxbHbmLazyWithNoProxyEnum hbmLazy, + JaxbHbmFetchStyleEnum hbmFetch, + JaxbHbmOuterJoinEnum hbmOuterJoin, + Boolean constrained, + ToOneAttribute fetchable) { + FetchType laziness = FetchType.LAZY; + JaxbSingularFetchMode fetch = JaxbSingularFetchMode.SELECT; + + if (hbmLazy != null) { + if (hbmLazy.equals( JaxbHbmLazyWithNoProxyEnum.FALSE )) { + laziness = FetchType.EAGER; + } + else if (hbmLazy.equals( JaxbHbmLazyWithNoProxyEnum.NO_PROXY )) { + // TODO: @LazyToOne(LazyToOneOption.PROXY) or @LazyToOne(LazyToOneOption.NO_PROXY) + } + } + + // allow fetch style to override laziness, if necessary + if (constrained != null && ! constrained) { + // NOTE SPECIAL CASE: one-to-one constrained=false cannot be proxied, so default to join and non-lazy + laziness = FetchType.EAGER; + fetch = JaxbSingularFetchMode.JOIN; + } + else { + if (hbmFetch == null) { + if (hbmOuterJoin != null && hbmOuterJoin.equals( JaxbHbmOuterJoinEnum.TRUE ) ) { + laziness = FetchType.EAGER; + fetch = JaxbSingularFetchMode.JOIN; + } + } + else { + if (hbmFetch.equals( JaxbHbmFetchStyleEnum.JOIN ) ) { + laziness = FetchType.EAGER; + fetch = JaxbSingularFetchMode.JOIN; + } + } + } + + fetchable.setFetch( laziness ); + fetchable.setFetchMode( fetch ); + } + + // ToMany + private void transferFetchable( + JaxbHbmLazyWithExtraEnum hbmLazy, + JaxbHbmFetchStyleWithSubselectEnum hbmFetch, + JaxbHbmOuterJoinEnum hbmOuterJoin, + CollectionAttribute fetchable) { + FetchType laziness = FetchType.LAZY; + JaxbPluralFetchMode fetch = JaxbPluralFetchMode.SELECT; + + if (hbmLazy != null) { + if (hbmLazy.equals( JaxbHbmLazyWithExtraEnum.EXTRA )) { + throw new MappingException( "HBM transformation: extra lazy not yet supported.", origin ); + } + else if (hbmLazy.equals( JaxbHbmLazyWithExtraEnum.FALSE )) { + laziness = FetchType.EAGER; + } + } + + // allow fetch style to override laziness, if necessary + if (hbmFetch == null) { + if (hbmOuterJoin != null && hbmOuterJoin.equals( JaxbHbmOuterJoinEnum.TRUE ) ) { + laziness = FetchType.EAGER; + fetch = JaxbPluralFetchMode.JOIN; + } + } + else { + if (hbmFetch.equals( JaxbHbmFetchStyleWithSubselectEnum.JOIN ) ) { + laziness = FetchType.EAGER; + fetch = JaxbPluralFetchMode.JOIN; + } + else if (hbmFetch.equals( JaxbHbmFetchStyleWithSubselectEnum.SUBSELECT ) ) { + fetch = JaxbPluralFetchMode.SUBSELECT; + } + } + + fetchable.setFetch( laziness ); + fetchable.setFetchMode( fetch ); + } + + // KeyManyToOne + private FetchType convert(JaxbHbmLazyEnum hbmLazy) { + if ( hbmLazy != null && "false".equalsIgnoreCase( hbmLazy.value() ) ) { + return FetchType.EAGER; + } + else { + // proxy is HBM default + return FetchType.LAZY; + } + } + + private OnDeleteAction convert(JaxbHbmOnDeleteEnum hbmOnDelete) { + return hbmOnDelete == JaxbHbmOnDeleteEnum.CASCADE ? OnDeleteAction.CASCADE : OnDeleteAction.NO_ACTION; + } + + private JaxbHbmFilter convert(JaxbHbmFilterType hbmFilter) { + final JaxbHbmFilter filter = new JaxbHbmFilter(); + filter.setName( hbmFilter.getName() ); + + final boolean shouldAutoInjectAliases = hbmFilter.getAutoAliasInjection() == null + || hbmFilter.getAutoAliasInjection().equalsIgnoreCase( "true" ); + + filter.setAutoAliasInjection( shouldAutoInjectAliases ); + filter.setCondition( hbmFilter.getCondition() ); + + for ( Serializable content : hbmFilter.getContent() ) { + if ( content instanceof String ) { + filter.setCondition( (String) content ); + } + else { + final JaxbHbmFilterAliasMappingType hbmAliasMapping = (JaxbHbmFilterAliasMappingType) content; + final JaxbHbmFilter.JaxbAliases aliasMapping = new JaxbHbmFilter.JaxbAliases(); + aliasMapping.setAlias( hbmAliasMapping.getAlias() ); + aliasMapping.setEntity( hbmAliasMapping.getEntity() ); + aliasMapping.setTable( hbmAliasMapping.getTable() ); + filter.getContent().add( aliasMapping ); + } + } + + return filter; + } + + private JaxbCascadeType convertCascadeType(String s) { + final JaxbCascadeType cascadeType = new JaxbCascadeType(); + + if ( isNotEmpty( s ) ) { + s = s.toLowerCase( Locale.ROOT ).replaceAll( " ", "" ); + final String[] split = s.split( "," ); + for ( String hbmCascade : split ) { + if ( hbmCascade.contains( "all" ) ) { + cascadeType.setCascadeAll( new JaxbEmptyType() ); + } + if ( hbmCascade.contains( "persist" ) ) { + cascadeType.setCascadePersist( new JaxbEmptyType() ); + } + if (hbmCascade.contains( "merge" ) ) { + cascadeType.setCascadeMerge( new JaxbEmptyType() ); + } + if (hbmCascade.contains( "refresh" ) ) { + cascadeType.setCascadeRefresh( new JaxbEmptyType() ); + } + if (hbmCascade.contains( "save-update" ) ) { + cascadeType.setCascadeSaveUpdate( new JaxbEmptyType() ); + } + if (hbmCascade.contains( "evict" ) || hbmCascade.contains( "detach" ) ) { + cascadeType.setCascadeDetach( new JaxbEmptyType() ); + } + if (hbmCascade.contains( "replicate" ) ) { + cascadeType.setCascadeReplicate( new JaxbEmptyType() ); + } + if (hbmCascade.contains( "lock" ) ) { + cascadeType.setCascadeLock( new JaxbEmptyType() ); + } + if (hbmCascade.contains( "delete" ) ) { + cascadeType.setCascadeDelete( new JaxbEmptyType() ); + } + } + } + return cascadeType; + } + + private boolean isOrphanRemoval(String s) { + return isNotEmpty( s ) + && s.toLowerCase( Locale.ROOT ).contains( "orphan" ); + } + + private String getFullyQualifiedClassName(String className) { + // todo : right now we do both, we set the package into the XML and qualify the names; pick one... + // 1) pass the names through as-is and set the package into the XML; the orm.xml reader + // would apply the package as needed + // 2) qualify the name that we write into the XML, but the do not set the package into the XML; + // if going this route, would be better to leverage the normal hierarchical lookup for package + // names which would mean passing along MappingDefaults (or maybe even the full "binding context") + + final String defaultPackageName = ormRoot.getPackage(); + if ( isNotEmpty( className ) + && className.indexOf( '.' ) < 0 + && isNotEmpty( defaultPackageName ) ) { + className = StringHelper.qualify( defaultPackageName, className ); + } + return className; + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/SourceColumnAdapter.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/SourceColumnAdapter.java new file mode 100644 index 0000000000..b21583fba7 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/SourceColumnAdapter.java @@ -0,0 +1,30 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. + */ +package org.hibernate.boot.jaxb.hbm.transform; + +/** + * @author Steve Ebersole + */ +public interface SourceColumnAdapter { + String getName(); + Boolean isNotNull(); + Boolean isUnique(); + Integer getLength(); + Integer getPrecision(); + Integer getScale(); + String getSqlType(); + + String getComment(); + String getCheck(); + String getDefault(); + + String getIndex(); + String getUniqueKey(); + + String getRead(); + String getWrite(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/SourceColumnAdapterJaxbHbmColumnType.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/SourceColumnAdapterJaxbHbmColumnType.java new file mode 100644 index 0000000000..b1ab9ba67f --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/SourceColumnAdapterJaxbHbmColumnType.java @@ -0,0 +1,90 @@ +/* + * 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.boot.jaxb.hbm.transform; + +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmColumnType; + +/** + * @author Steve Ebersole + */ +public class SourceColumnAdapterJaxbHbmColumnType implements SourceColumnAdapter { + private final JaxbHbmColumnType hbmColumn; + + public SourceColumnAdapterJaxbHbmColumnType(JaxbHbmColumnType hbmColumn) { + this.hbmColumn = hbmColumn; + } + + @Override + public String getName() { + return hbmColumn.getName(); + } + + @Override + public Boolean isNotNull() { + return hbmColumn.isNotNull(); + } + + @Override + public Boolean isUnique() { + return hbmColumn.isUnique(); + } + + @Override + public Integer getLength() { + return hbmColumn.getLength(); + } + + @Override + public Integer getPrecision() { + return hbmColumn.getPrecision(); + } + + @Override + public Integer getScale() { + return hbmColumn.getScale(); + } + + @Override + public String getSqlType() { + return hbmColumn.getSqlType(); + } + + @Override + public String getComment() { + return hbmColumn.getComment(); + } + + @Override + public String getCheck() { + return hbmColumn.getCheck(); + } + + @Override + public String getDefault() { + return hbmColumn.getDefault(); + } + + @Override + public String getIndex() { + return hbmColumn.getIndex(); + } + + @Override + public String getUniqueKey() { + return hbmColumn.getUniqueKey(); + } + + @Override + public String getRead() { + return hbmColumn.getRead(); + } + + @Override + public String getWrite() { + return hbmColumn.getWrite(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/TargetColumnAdapter.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/TargetColumnAdapter.java new file mode 100644 index 0000000000..0e0118a068 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/TargetColumnAdapter.java @@ -0,0 +1,42 @@ +/* + * 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.boot.jaxb.hbm.transform; + +/** + * @author Steve Ebersole + */ +interface TargetColumnAdapter { + void setName(String value); + + void setTable(String value); + + void setNullable(Boolean value); + + void setUnique(Boolean value); + + void setColumnDefinition(String value); + + void setLength(Integer value); + + void setPrecision(Integer value); + + void setScale(Integer value); + + void setDefault(String value); + + void setCheck(String value); + + void setComment(String value); + + void setRead(String value); + + void setWrite(String value); + + void setInsertable(Boolean value); + + void setUpdatable(Boolean value); +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/TargetColumnAdapterJaxbColumn.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/TargetColumnAdapterJaxbColumn.java new file mode 100644 index 0000000000..ce66d57b43 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/TargetColumnAdapterJaxbColumn.java @@ -0,0 +1,124 @@ +/* + * 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.boot.jaxb.hbm.transform; + +import org.hibernate.boot.jaxb.mapping.JaxbColumn; + +/** + * @author Steve Ebersole + */ +public class TargetColumnAdapterJaxbColumn implements TargetColumnAdapter { + private final JaxbColumn jaxbColumn; + + public TargetColumnAdapterJaxbColumn(ColumnDefaults columnDefaults) { + this( new JaxbColumn(), columnDefaults ); + } + + public TargetColumnAdapterJaxbColumn(JaxbColumn jaxbColumn, ColumnDefaults columnDefaults) { + this.jaxbColumn = jaxbColumn; + this.jaxbColumn.setLength( columnDefaults.getLength() ); + this.jaxbColumn.setScale( columnDefaults.getScale() ); + this.jaxbColumn.setPrecision( columnDefaults.getPrecision() ); + this.jaxbColumn.setNullable( columnDefaults.isNullable() ); + this.jaxbColumn.setUnique( columnDefaults.isUnique() ); + this.jaxbColumn.setInsertable( columnDefaults.isInsertable() ); + this.jaxbColumn.setUpdatable( columnDefaults.isUpdateable() ); + } + + public JaxbColumn getTargetColumn() { + return jaxbColumn; + } + + @Override + public void setName(String value) { + jaxbColumn.setName( value ); + } + + @Override + public void setTable(String value) { + jaxbColumn.setTable( value ); + } + + @Override + public void setNullable(Boolean value) { + if ( value != null ) { + jaxbColumn.setNullable( value ); + } + } + + @Override + public void setUnique(Boolean value) { + if ( value != null ) { + jaxbColumn.setUnique( value ); + } + } + + @Override + public void setInsertable(Boolean value) { + if ( value != null ) { + jaxbColumn.setInsertable( value ); + } + } + + @Override + public void setUpdatable(Boolean value) { + if ( value != null ) { + jaxbColumn.setUpdatable( value ); + } + } + + @Override + public void setLength(Integer value) { + if ( value != null ) { + jaxbColumn.setLength( value ); + } + } + + @Override + public void setPrecision(Integer value) { + if ( value != null ) { + jaxbColumn.setPrecision( value ); + } + } + + @Override + public void setScale(Integer value) { + if ( value != null ) { + jaxbColumn.setScale( value ); + } + } + + @Override + public void setColumnDefinition(String value) { + jaxbColumn.setColumnDefinition( value ); + } + + @Override + public void setDefault(String value) { + jaxbColumn.setDefault( value ); + } + + @Override + public void setCheck(String value) { + jaxbColumn.setCheck( value ); + } + + @Override + public void setComment(String value) { + jaxbColumn.setComment( value ); + } + + @Override + public void setRead(String value) { + jaxbColumn.setRead( value ); + } + + @Override + public void setWrite(String value) { + jaxbColumn.setWrite( value ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/TargetColumnAdapterJaxbJoinColumn.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/TargetColumnAdapterJaxbJoinColumn.java new file mode 100644 index 0000000000..f8331ac706 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/TargetColumnAdapterJaxbJoinColumn.java @@ -0,0 +1,107 @@ +/* + * 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.boot.jaxb.hbm.transform; + +import org.hibernate.boot.jaxb.mapping.JaxbJoinColumn; + +/** + * @author Steve Ebersole + */ +public class TargetColumnAdapterJaxbJoinColumn implements TargetColumnAdapter { + private final JaxbJoinColumn jaxbColumn; + + public TargetColumnAdapterJaxbJoinColumn(ColumnDefaults columnDefaults) { + this( new JaxbJoinColumn(), columnDefaults ); + } + + public TargetColumnAdapterJaxbJoinColumn(JaxbJoinColumn jaxbColumn, ColumnDefaults columnDefaults) { + this.jaxbColumn = jaxbColumn; + this.jaxbColumn.setNullable( columnDefaults.isNullable() ); + this.jaxbColumn.setUnique( columnDefaults.isUnique() ); + this.jaxbColumn.setInsertable( columnDefaults.isInsertable() ); + this.jaxbColumn.setUpdatable( columnDefaults.isUpdateable() ); + } + + public JaxbJoinColumn getTargetColumn() { + return jaxbColumn; + } + + @Override + public void setName(String value) { + jaxbColumn.setName( value ); + } + + @Override + public void setTable(String value) { + jaxbColumn.setTable( value ); + } + + @Override + public void setNullable(Boolean value) { + if ( value != null ) { + jaxbColumn.setNullable( value ); + } + } + + @Override + public void setUnique(Boolean value) { + if ( value != null ) { + jaxbColumn.setUnique( value ); + } + } + + @Override + public void setInsertable(Boolean value) { + if ( value != null ) { + jaxbColumn.setInsertable( value ); + } + } + + @Override + public void setUpdatable(Boolean value) { + if ( value != null ) { + jaxbColumn.setUpdatable( value ); + } + } + + @Override + public void setLength(Integer value) { + } + + @Override + public void setPrecision(Integer value) { + } + + @Override + public void setScale(Integer value) { + } + + @Override + public void setColumnDefinition(String value) { + jaxbColumn.setColumnDefinition( value ); + } + + @Override + public void setDefault(String value) { + } + + @Override + public void setCheck(String value) { + } + + @Override + public void setComment(String value) { + } + + @Override + public void setRead(String value) { + } + + @Override + public void setWrite(String value) { + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/UnsupportedFeatureHandling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/UnsupportedFeatureHandling.java new file mode 100644 index 0000000000..b3bd29a5b3 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/transform/UnsupportedFeatureHandling.java @@ -0,0 +1,64 @@ +/* + * 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.boot.jaxb.hbm.transform; + +import java.util.function.Function; + +/** + * How to handle features in the transformed `hbm.xml` which are not supported + * in the `mapping.xml` XSD + * + * @author Steve Ebersole + */ +public enum UnsupportedFeatureHandling { + /** + * Throw an exception. + */ + ERROR, + /** + * Similar to {@link #IGNORE} except that we log a warning + */ + WARN, + /** + * Simply ignore the feature. Logs a debug message + */ + IGNORE, + /** + * Pick the closest mapping, if possible. Falls back to {@link #IGNORE} if there is no close match + */ + PICK; + + public static UnsupportedFeatureHandling fromSetting(Object value) { + return fromSetting( value, (v) -> null ); + } + + public static UnsupportedFeatureHandling fromSetting(Object value, UnsupportedFeatureHandling defaultValue) { + return fromSetting( value, (v) -> defaultValue ); + } + + public static UnsupportedFeatureHandling fromSetting(Object value, Function defaultValueSupplier) { + if ( value != null ) { + if ( value instanceof UnsupportedFeatureHandling ) { + return (UnsupportedFeatureHandling) value; + } + + if ( ERROR.name().equalsIgnoreCase( value.toString() ) ) { + return ERROR; + } + + if ( IGNORE.name().equalsIgnoreCase( value.toString() ) ) { + return IGNORE; + } + + if ( PICK.name().equalsIgnoreCase( value.toString() ) ) { + return PICK; + } + } + + return defaultValueSupplier.apply( value ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/AbstractBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/AbstractBinder.java index a4775c3462..5b158e288c 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/AbstractBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/AbstractBinder.java @@ -2,14 +2,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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ package org.hibernate.boot.jaxb.internal; import java.io.InputStream; -import jakarta.xml.bind.JAXBContext; -import jakarta.xml.bind.JAXBException; -import jakarta.xml.bind.Unmarshaller; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; @@ -19,41 +16,36 @@ import javax.xml.transform.Source; import javax.xml.validation.Schema; import org.hibernate.boot.MappingException; +import org.hibernate.boot.ResourceStreamLocator; import org.hibernate.boot.jaxb.Origin; import org.hibernate.boot.jaxb.internal.stax.BufferedXMLEventReader; import org.hibernate.boot.jaxb.internal.stax.LocalXmlResourceResolver; import org.hibernate.boot.jaxb.spi.Binder; import org.hibernate.boot.jaxb.spi.Binding; -import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; - import org.hibernate.internal.util.StringHelper; + import org.jboss.logging.Logger; +import jakarta.xml.bind.JAXBContext; +import jakarta.xml.bind.JAXBException; +import jakarta.xml.bind.Unmarshaller; + /** * @author Steve Ebersole */ -public abstract class AbstractBinder implements Binder { +public abstract class AbstractBinder implements Binder { private static final Logger log = Logger.getLogger( AbstractBinder.class ); private final LocalXmlResourceResolver xmlResourceResolver; - private final boolean validateXml; - @SuppressWarnings("unused") - protected AbstractBinder(ClassLoaderService classLoaderService) { - this( classLoaderService, true ); + protected AbstractBinder(ResourceStreamLocator resourceStreamLocator) { + this.xmlResourceResolver = new LocalXmlResourceResolver( resourceStreamLocator ); } - protected AbstractBinder(ClassLoaderService classLoaderService, boolean validateXml) { - this.xmlResourceResolver = new LocalXmlResourceResolver( classLoaderService ); - this.validateXml = validateXml; - } - - public boolean isValidationEnabled() { - return validateXml; - } + public abstract boolean isValidationEnabled(); @Override - public Binding bind(InputStream stream, Origin origin) { + public Binding bind(InputStream stream, Origin origin) { final XMLEventReader eventReader = createReader( stream, origin ); try { return doBind( eventReader, origin ); @@ -81,7 +73,7 @@ public abstract class AbstractBinder implements Binder { } @Override - public Binding bind(Source source, Origin origin) { + public Binding bind(Source source, Origin origin) { final XMLEventReader eventReader = createReader( source, origin ); return doBind( eventReader, origin ); } @@ -98,7 +90,7 @@ public abstract class AbstractBinder implements Binder { } } - private Binding doBind(XMLEventReader eventReader, Origin origin) { + private Binding doBind(XMLEventReader eventReader, Origin origin) { try { final StartElement rootElementStartEvent = seekRootElementStartEvent( eventReader, origin ); return doBind( eventReader, rootElementStartEvent, origin ); @@ -107,7 +99,7 @@ public abstract class AbstractBinder implements Binder { try { eventReader.close(); } - catch ( Exception e ) { + catch (Exception e) { log.debug( "Unable to close StAX reader", e ); } @@ -149,15 +141,14 @@ public abstract class AbstractBinder implements Binder { return rootElementStartEvent.asStartElement(); } - protected abstract Binding doBind(XMLEventReader staxEventReader, StartElement rootElementStartEvent, Origin origin); + protected abstract Binding doBind(XMLEventReader staxEventReader, StartElement rootElementStartEvent, Origin origin); @SuppressWarnings("unused") protected static boolean hasNamespace(StartElement startElement) { return StringHelper.isNotEmpty( startElement.getName().getNamespaceURI() ); } - @SuppressWarnings("unchecked") - protected T jaxb(XMLEventReader reader, Schema xsd, JAXBContext jaxbContext, Origin origin) { + protected X jaxb(XMLEventReader reader, Schema xsd, JAXBContext jaxbContext, Origin origin) { final ContextProvidingValidationEventHandler handler = new ContextProvidingValidationEventHandler(); try { @@ -170,7 +161,8 @@ public abstract class AbstractBinder implements Binder { } unmarshaller.setEventHandler( handler ); - return (T) unmarshaller.unmarshal( reader ); + //noinspection unchecked + return (X) unmarshaller.unmarshal( reader ); } catch ( JAXBException e ) { throw new MappingException( diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/ContextProvidingValidationEventHandler.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/ContextProvidingValidationEventHandler.java index bd0dad1733..c7b47db2bf 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/ContextProvidingValidationEventHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/ContextProvidingValidationEventHandler.java @@ -2,7 +2,7 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ package org.hibernate.boot.jaxb.internal; @@ -15,7 +15,7 @@ import jakarta.xml.bind.ValidationEventLocator; * * @author Steve Ebersole */ -class ContextProvidingValidationEventHandler implements ValidationEventHandler { +public class ContextProvidingValidationEventHandler implements ValidationEventHandler { private int lineNumber; private int columnNumber; private String message; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java index 6cf11d0148..8b48036dcd 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java @@ -2,46 +2,205 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ package org.hibernate.boot.jaxb.internal; -import jakarta.xml.bind.JAXBContext; -import jakarta.xml.bind.JAXBException; +import java.util.function.Function; +import java.util.function.Supplier; import javax.xml.stream.XMLEventFactory; import javax.xml.stream.XMLEventReader; import javax.xml.stream.events.StartElement; +import org.hibernate.Internal; +import org.hibernate.boot.ResourceStreamLocator; import org.hibernate.boot.UnsupportedOrmXsdVersionException; +import org.hibernate.boot.jaxb.JaxbLogger; import org.hibernate.boot.jaxb.Origin; import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping; +import org.hibernate.boot.jaxb.hbm.transform.HbmXmlTransformer; +import org.hibernate.boot.jaxb.hbm.transform.UnsupportedFeatureHandling; import org.hibernate.boot.jaxb.internal.stax.HbmEventReader; import org.hibernate.boot.jaxb.internal.stax.JpaOrmXmlEventReader; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; +import org.hibernate.boot.jaxb.internal.stax.MappingEventReader; +import org.hibernate.boot.jaxb.mapping.JaxbEntityMappings; +import org.hibernate.boot.jaxb.spi.BindableMappingDescriptor; import org.hibernate.boot.jaxb.spi.Binding; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.xsd.MappingXsdSupport; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.engine.config.spi.ConfigurationService; +import org.hibernate.internal.log.DeprecationLogger; import org.hibernate.internal.util.config.ConfigurationException; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.service.spi.ServiceRegistryImplementor; import org.jboss.logging.Logger; +import jakarta.xml.bind.JAXBContext; +import jakarta.xml.bind.JAXBException; + +import static org.hibernate.engine.config.spi.StandardConverters.BOOLEAN; + /** + * Responsible for coordinating binding of mapping XML documents into + * JAXB representations, producing {@link Binding} references. + * * @author Steve Ebersole */ -public class MappingBinder extends AbstractBinder { +public class MappingBinder extends AbstractBinder { private static final Logger log = Logger.getLogger( MappingBinder.class ); private final XMLEventFactory xmlEventFactory = XMLEventFactory.newInstance(); + private final Supplier optionsAccess; + private final Supplier unsupportedHandlingAccess; + private JAXBContext hbmJaxbContext; private JAXBContext entityMappingsJaxbContext; - public MappingBinder(ClassLoaderService classLoaderService, boolean validateXml) { - super( classLoaderService, validateXml ); + public interface Options { + boolean validateMappings(); + + boolean transformHbmMappings(); + } + + public static final Options VALIDATING = new Options() { + @Override + public boolean validateMappings() { + return true; + } + + @Override + public boolean transformHbmMappings() { + return false; + } + }; + + public static final Options NON_VALIDATING = new Options() { + @Override + public boolean validateMappings() { + return true; + } + + @Override + public boolean transformHbmMappings() { + return false; + } + }; + + /** + * Full constructor + */ + public MappingBinder( + ResourceStreamLocator resourceStreamLocator, + Supplier optionsAccess, + Supplier unsupportedHandlingAccess) { + super( resourceStreamLocator ); + this.optionsAccess = optionsAccess; + this.unsupportedHandlingAccess = unsupportedHandlingAccess; + } + + /** + * Full non-lazy constructor + */ + private MappingBinder( + ResourceStreamLocator resourceStreamLocator, + Options options, + UnsupportedFeatureHandling unsupportedHandling) { + this( resourceStreamLocator, () -> options, () -> unsupportedHandling ); + } + + public MappingBinder( + ResourceStreamLocator resourceStreamLocator, + Function settingsAccess) { + super( resourceStreamLocator == null ? MappingBinder.class.getClassLoader()::getResourceAsStream : resourceStreamLocator ); + + if ( settingsAccess == null ) { + this.optionsAccess = () -> VALIDATING; + this.unsupportedHandlingAccess = () -> UnsupportedFeatureHandling.ERROR; + } + else { + this.optionsAccess = () -> new Options() { + @Override + public boolean validateMappings() { + final Object setting = settingsAccess.apply( AvailableSettings.VALIDATE_XML ); + if ( setting == null ) { + return false; + } + return BOOLEAN.convert( setting ); + } + + @Override + public boolean transformHbmMappings() { + final Object setting = settingsAccess.apply( AvailableSettings.TRANSFORM_HBM_XML ); + if ( setting == null ) { + return false; + } + return BOOLEAN.convert( setting ); + } + }; + + this.unsupportedHandlingAccess = () -> { + final Object setting = settingsAccess.apply( AvailableSettings.TRANSFORM_HBM_XML_FEATURE_HANDLING ); + return UnsupportedFeatureHandling.fromSetting( setting, UnsupportedFeatureHandling.ERROR ); + }; + } + } + + public MappingBinder(ServiceRegistry serviceRegistry) { + this( + serviceRegistry.getService( ClassLoaderService.class ), + (settingName) -> { + final ConfigurationService configurationService; + if ( serviceRegistry instanceof ServiceRegistryImplementor ) { + final ServiceRegistryImplementor serviceRegistryImplementor = (ServiceRegistryImplementor) serviceRegistry; + configurationService = serviceRegistryImplementor.fromRegistryOrChildren( ConfigurationService.class ); + } + else { + configurationService = serviceRegistry.getService( ConfigurationService.class ); + } + + return configurationService == null ? null : configurationService.getSettings().get( settingName ); + } + ); + } + + /** + * Constructor used by the Gradle plugin + */ + public MappingBinder(ResourceStreamLocator resourceStreamLocator, UnsupportedFeatureHandling unsupportedHandling) { + this( + resourceStreamLocator, + new Options() { + @Override + public boolean validateMappings() { + return false; + } + + @Override + public boolean transformHbmMappings() { + return false; + } + }, + unsupportedHandling + ); + } + + /** + * Constructor used everywhere else + */ + public MappingBinder(ResourceStreamLocator resourceStreamLocator, Options options) { + this( resourceStreamLocator, options, UnsupportedFeatureHandling.ERROR ); } @Override - protected Binding doBind( + public boolean isValidationEnabled() { + return optionsAccess.get().validateMappings(); + } + + @Override + protected Binding doBind( XMLEventReader staxEventReader, StartElement rootElementStartEvent, Origin origin) { @@ -51,17 +210,30 @@ public class MappingBinder extends AbstractBinder { log.debugf( "Performing JAXB binding of hbm.xml document : %s", origin.toString() ); } - XMLEventReader hbmReader = new HbmEventReader( staxEventReader, xmlEventFactory ); - JaxbHbmHibernateMapping hbmBindings = jaxb( hbmReader, MappingXsdSupport.INSTANCE.hbmXsd().getSchema(), hbmJaxbContext(), origin ); - return new Binding<>( hbmBindings, origin ); + final XMLEventReader hbmReader = new HbmEventReader( staxEventReader, xmlEventFactory ); + final JaxbHbmHibernateMapping hbmBindings = jaxb( hbmReader, MappingXsdSupport.INSTANCE.hbmXsd() + .getSchema(), hbmJaxbContext(), origin ); + + if ( optionsAccess.get().transformHbmMappings() ) { + JaxbLogger.JAXB_LOGGER.tracef( "Performing on-the-fly hbm.xml -> mapping.xml transformation - %s ", origin ); + //noinspection unchecked + return new Binding<>( (X) HbmXmlTransformer.transform( hbmBindings, origin, unsupportedHandlingAccess::get ), origin ); + } + + DeprecationLogger.DEPRECATION_LOGGER.logDeprecatedHbmXmlProcessing( origin.getType(), origin.getName() ); + //noinspection unchecked + return new Binding<>( (X) hbmBindings, origin ); } else { + assert "entity-mappings".equals( rootElementLocalName ); try { log.debugf( "Performing JAXB binding of orm.xml document : %s", origin.toString() ); - XMLEventReader reader = new JpaOrmXmlEventReader( staxEventReader, xmlEventFactory ); - JaxbEntityMappings bindingRoot = jaxb( reader, MappingXsdSupport.INSTANCE.latestJpaDescriptor().getSchema(), entityMappingsJaxbContext(), origin ); - return new Binding<>( bindingRoot, origin ); + final XMLEventReader reader = new MappingEventReader( staxEventReader, xmlEventFactory ); + final JaxbEntityMappings bindingRoot = jaxb( reader, MappingXsdSupport.latestDescriptor() + .getSchema(), mappingJaxbContext(), origin ); + //noinspection unchecked + return new Binding<>( (X) bindingRoot, origin ); } catch (JpaOrmXmlEventReader.BadVersionException e) { throw new UnsupportedOrmXsdVersionException( e.getRequestedVersion(), origin ); @@ -74,19 +246,20 @@ public class MappingBinder extends AbstractBinder { try { hbmJaxbContext = JAXBContext.newInstance( JaxbHbmHibernateMapping.class ); } - catch ( JAXBException e ) { + catch (JAXBException e) { throw new ConfigurationException( "Unable to build hbm.xml JAXBContext", e ); } } return hbmJaxbContext; } - private JAXBContext entityMappingsJaxbContext() { + @Internal + public JAXBContext mappingJaxbContext() { if ( entityMappingsJaxbContext == null ) { try { entityMappingsJaxbContext = JAXBContext.newInstance( JaxbEntityMappings.class ); } - catch ( JAXBException e ) { + catch (JAXBException e) { throw new ConfigurationException( "Unable to build orm.xml JAXBContext", e ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/LocalSchemaLocator.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/LocalSchemaLocator.java index 8e0a733915..0332bb92bd 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/LocalSchemaLocator.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/LocalSchemaLocator.java @@ -18,18 +18,16 @@ import org.jboss.logging.Logger; /** * Helper for resolving XML Schema references locally. - *

- * Note that *by design* we always use our ClassLoader to perform the lookups here. + * + * @implNote *By design* we always use our ClassLoader to perform the lookups here. * * @author Steve Ebersole */ public class LocalSchemaLocator { private static final Logger log = Logger.getLogger( LocalSchemaLocator.class ); - /** - * Disallow direct instantiation - */ private LocalSchemaLocator() { + // Disallow direct instantiation } /** diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/LocalXmlResourceResolver.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/LocalXmlResourceResolver.java index bff054b09a..2e5ea0ec3a 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/LocalXmlResourceResolver.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/LocalXmlResourceResolver.java @@ -2,7 +2,7 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ package org.hibernate.boot.jaxb.internal.stax; @@ -11,9 +11,10 @@ import java.io.InputStream; import java.net.URL; import javax.xml.stream.XMLStreamException; -import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; +import org.hibernate.boot.ResourceStreamLocator; import org.hibernate.boot.xsd.ConfigXsdSupport; import org.hibernate.boot.xsd.MappingXsdSupport; +import org.hibernate.boot.xsd.XsdDescriptor; import org.jboss.logging.Logger; @@ -27,10 +28,10 @@ public class LocalXmlResourceResolver implements javax.xml.stream.XMLResolver { public static final String CLASSPATH_EXTENSION_URL_BASE = "classpath://"; - private final ClassLoaderService classLoaderService; + private final ResourceStreamLocator resourceStreamLocator; - public LocalXmlResourceResolver(ClassLoaderService classLoaderService) { - this.classLoaderService = classLoaderService; + public LocalXmlResourceResolver(ResourceStreamLocator resourceStreamLocator) { + this.resourceStreamLocator = resourceStreamLocator; } @Override @@ -39,42 +40,45 @@ public class LocalXmlResourceResolver implements javax.xml.stream.XMLResolver { if ( namespace != null ) { log.debugf( "Interpreting namespace : %s", namespace ); + if ( MappingXsdSupport._310.getNamespaceUri().matches( namespace ) ) { + return openUrlStream( MappingXsdSupport._310 ); + } if ( MappingXsdSupport.jpa10.getNamespaceUri().matches( namespace ) ) { // JPA 1.0 and 2.0 share the same namespace URI - return openUrlStream( LocalSchemaLocator.resolveLocalSchemaUrl( MappingXsdSupport.jpa10.getLocalResourceName() ) ); + return openUrlStream( MappingXsdSupport.jpa10 ); } else if ( MappingXsdSupport.jpa21.getNamespaceUri().matches( namespace ) ) { // JPA 2.1 and 2.2 share the same namespace URI - return openUrlStream( LocalSchemaLocator.resolveLocalSchemaUrl( MappingXsdSupport.jpa21.getLocalResourceName() ) ); + return openUrlStream( MappingXsdSupport.jpa21 ); } else if ( MappingXsdSupport.jpa30.getNamespaceUri().matches( namespace ) ) { - return openUrlStream( LocalSchemaLocator.resolveLocalSchemaUrl( MappingXsdSupport.jpa30.getLocalResourceName() ) ); + return openUrlStream( MappingXsdSupport.jpa30 ); } else if ( MappingXsdSupport.jpa31.getNamespaceUri().matches( namespace ) ) { - return openUrlStream( LocalSchemaLocator.resolveLocalSchemaUrl( MappingXsdSupport.jpa31.getLocalResourceName() ) ); + return openUrlStream( MappingXsdSupport.jpa31 ); } else if ( ConfigXsdSupport.getJPA10().getNamespaceUri().matches( namespace ) ) { // JPA 1.0 and 2.0 share the same namespace URI - return openUrlStream( LocalSchemaLocator.resolveLocalSchemaUrl( ConfigXsdSupport.getJPA10().getLocalResourceName() ) ); + return openUrlStream( ConfigXsdSupport.getJPA10() ); } else if ( ConfigXsdSupport.getJPA21().getNamespaceUri().matches( namespace ) ) { // JPA 2.1 and 2.2 share the same namespace URI - return openUrlStream( LocalSchemaLocator.resolveLocalSchemaUrl( ConfigXsdSupport.getJPA21().getLocalResourceName() ) ); + return openUrlStream( ConfigXsdSupport.getJPA21() ); } else if ( ConfigXsdSupport.getJPA30().getNamespaceUri().matches( namespace ) ) { - return openUrlStream( LocalSchemaLocator.resolveLocalSchemaUrl( ConfigXsdSupport.getJPA30().getLocalResourceName() ) ); + return openUrlStream( ConfigXsdSupport.getJPA30() ); } else if ( ConfigXsdSupport.getJPA31().getNamespaceUri().matches( namespace ) ) { - return openUrlStream( LocalSchemaLocator.resolveLocalSchemaUrl( ConfigXsdSupport.getJPA31().getLocalResourceName() ) ); + return openUrlStream( ConfigXsdSupport.getJPA31() ); } else if ( MappingXsdSupport.hibernateMappingXml.getNamespaceUri().matches( namespace ) ) { - return openUrlStream( LocalSchemaLocator.resolveLocalSchemaUrl( MappingXsdSupport.hibernateMappingXml.getLocalResourceName() ) ); + return openUrlStream( MappingXsdSupport.hibernateMappingXml ); } else if ( MappingXsdSupport.hbmXml.getNamespaceUri().matches( namespace ) ) { - return openUrlStream( LocalSchemaLocator.resolveLocalSchemaUrl( MappingXsdSupport.hbmXml.getLocalResourceName() ) ); + return openUrlStream( MappingXsdSupport.hbmXml ); } else if ( ConfigXsdSupport.cfgXsd().getNamespaceUri().matches( namespace ) ) { - return openUrlStream( LocalSchemaLocator.resolveLocalSchemaUrl( ConfigXsdSupport.cfgXsd().getLocalResourceName() ) ); + return openUrlStream( ConfigXsdSupport.cfgXsd() ); } } @@ -128,6 +132,10 @@ public class LocalXmlResourceResolver implements javax.xml.stream.XMLResolver { return null; } + private InputStream openUrlStream(XsdDescriptor xsdDescriptor) { + return openUrlStream( LocalSchemaLocator.resolveLocalSchemaUrl( xsdDescriptor.getLocalResourceName() ) ); + } + private InputStream openUrlStream(URL url) { try { return url.openStream(); @@ -139,7 +147,7 @@ public class LocalXmlResourceResolver implements javax.xml.stream.XMLResolver { private InputStream resolveInLocalNamespace(String path) { try { - return classLoaderService.locateResourceStream( path ); + return resourceStreamLocator.locateResourceStream( path ); } catch ( Throwable t ) { return null; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/MappingEventReader.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/MappingEventReader.java new file mode 100644 index 0000000000..8545eb3a88 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/stax/MappingEventReader.java @@ -0,0 +1,183 @@ +/* + * 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.boot.jaxb.internal.stax; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLEventFactory; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.Namespace; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +import javax.xml.stream.util.EventReaderDelegate; + +import org.hibernate.boot.xsd.MappingXsdSupport; + +/** + * StAX EVentReader for reading `mapping.xml` streams + * + * @author Steve Ebersole + * @author Hardy Ferentschik + */ +public class MappingEventReader extends EventReaderDelegate { + private static final String ROOT_ELEMENT_NAME = "entity-mappings"; + private static final String VERSION_ATTRIBUTE_NAME = "version"; + + private final XMLEventFactory xmlEventFactory; + + public MappingEventReader(XMLEventReader reader, XMLEventFactory xmlEventFactory) { + super( reader ); + this.xmlEventFactory = xmlEventFactory; + } + + @Override + public XMLEvent peek() throws XMLStreamException { + return wrap( super.peek() ); + } + + @Override + public XMLEvent nextEvent() throws XMLStreamException { + return wrap( super.nextEvent() ); + } + + private XMLEvent wrap(XMLEvent event) { + if ( event != null ) { + if ( event.isStartElement() ) { + return wrap( event.asStartElement() ); + } + else if ( event.isEndElement() ) { + return wrap( event.asEndElement() ); + } + } + return event; + } + + private StartElement wrap(StartElement startElement) { + final List newElementAttributeList = mapAttributes( startElement ); + final List newNamespaceList = mapNamespaces( startElement ); + + // Transfer the location info from the incoming event to the event factory + // so that the event we ask it to generate for us has the same location info + xmlEventFactory.setLocation( startElement.getLocation() ); + return xmlEventFactory.createStartElement( + new QName( MappingXsdSupport.latestDescriptor().getNamespaceUri(), startElement.getName().getLocalPart() ), + newElementAttributeList.iterator(), + newNamespaceList.iterator() + ); + } + + private List mapAttributes(StartElement startElement) { + final List mappedAttributes = new ArrayList<>(); + + final Iterator existingAttributesIterator = existingXmlAttributesIterator( startElement ); + while ( existingAttributesIterator.hasNext() ) { + final Attribute originalAttribute = existingAttributesIterator.next(); + final Attribute attributeToUse = mapAttribute( startElement, originalAttribute ); + mappedAttributes.add( attributeToUse ); + } + + return mappedAttributes; + } + + private Iterator existingXmlAttributesIterator(StartElement startElement) { + return startElement.getAttributes(); + } + + private Attribute mapAttribute(StartElement startElement, Attribute originalAttribute) { + // Here we look to see if this attribute is the JPA version attribute, and if so do 2 things: + // 1) validate its version attribute is valid + // 2) update its version attribute to the default version if not already + // + // NOTE : atm this is a very simple check using just the attribute's local name + // rather than checking its qualified name. It is possibly (though unlikely) + // that this could match on "other" version attributes in the same element + + if ( ROOT_ELEMENT_NAME.equals( startElement.getName().getLocalPart() ) ) { + if ( VERSION_ATTRIBUTE_NAME.equals( originalAttribute.getName().getLocalPart() ) ) { + final String specifiedVersion = originalAttribute.getValue(); + + if ( ! MappingXsdSupport.isValidJpaVersion( specifiedVersion ) ) { + throw new BadVersionException( specifiedVersion ); + } + + return xmlEventFactory.createAttribute( VERSION_ATTRIBUTE_NAME, MappingXsdSupport.latestDescriptor().getVersion() ); + } + } + + return originalAttribute; + } + + private List mapNamespaces(StartElement startElement) { + return mapNamespaces( existingXmlNamespacesIterator( startElement ) ); + } + + private List mapNamespaces(Iterator originalNamespaceIterator ) { + final List mappedNamespaces = new ArrayList<>(); + + while ( originalNamespaceIterator.hasNext() ) { + final Namespace originalNamespace = originalNamespaceIterator.next(); + final Namespace mappedNamespace = mapNamespace( originalNamespace ); + mappedNamespaces.add( mappedNamespace ); + } + + if ( mappedNamespaces.isEmpty() ) { + mappedNamespaces.add( xmlEventFactory.createNamespace( MappingXsdSupport.latestDescriptor().getNamespaceUri() ) ); + } + + return mappedNamespaces; + } + + @SuppressWarnings("unchecked") + private Iterator existingXmlNamespacesIterator(StartElement startElement) { + return startElement.getNamespaces(); + } + + private Namespace mapNamespace(Namespace originalNamespace) { + if ( MappingXsdSupport.shouldBeMappedToLatestJpaDescriptor( originalNamespace.getNamespaceURI() ) ) { + // this is a namespace "to map" so map it + return xmlEventFactory.createNamespace( + originalNamespace.getPrefix(), + MappingXsdSupport.latestDescriptor().getNamespaceUri() + ); + } + + return originalNamespace; + } + + private XMLEvent wrap(EndElement endElement) { + final List targetNamespaces = mapNamespaces( existingXmlNamespacesIterator( endElement ) ); + + // Transfer the location info from the incoming event to the event factory + // so that the event we ask it to generate for us has the same location info + xmlEventFactory.setLocation( endElement.getLocation() ); + return xmlEventFactory.createEndElement( + new QName( MappingXsdSupport.latestDescriptor().getNamespaceUri(), endElement.getName().getLocalPart() ), + targetNamespaces.iterator() + ); + } + + private Iterator existingXmlNamespacesIterator(EndElement endElement) { + return endElement.getNamespaces(); + } + + public static class BadVersionException extends RuntimeException { + private final String requestedVersion; + + public BadVersionException(String requestedVersion) { + this.requestedVersion = requestedVersion; + } + + public String getRequestedVersion() { + return requestedVersion; + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/AssociationAttribute.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/AssociationAttribute.java similarity index 71% rename from hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/AssociationAttribute.java rename to hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/AssociationAttribute.java index f9784577ab..1d1d2f8394 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/AssociationAttribute.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/AssociationAttribute.java @@ -1,13 +1,17 @@ /* * 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 + * 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.boot.jaxb.mapping.spi; +package org.hibernate.boot.jaxb.mapping; +/** + * JAXB binding interface for association attributes (to-one and plural mappings) + * + * @author Steve Ebersole + */ public interface AssociationAttribute extends PersistentAttribute, FetchableAttribute { - JaxbJoinTable getJoinTable(); void setJoinTable(JaxbJoinTable value); @@ -19,5 +23,4 @@ public interface AssociationAttribute extends PersistentAttribute, FetchableAttr String getTargetEntity(); void setTargetEntity(String value); - } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/AttributesContainer.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/AttributesContainer.java new file mode 100644 index 0000000000..47f9455a55 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/AttributesContainer.java @@ -0,0 +1,40 @@ +/* + * 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.boot.jaxb.mapping; + +import java.util.List; + +/** + * JAXB binding interface for commonality between things which contain attributes. + * + * @apiNote In the mapping XSD, this equates to the `attributes` and `embeddable-attributes` + * nodes rather than the ManagedTypes themselves. + * + * @author Strong Liu + * @author Steve Ebersole + */ +public interface AttributesContainer { + List getBasicAttributes(); + + List getEmbeddedAttributes(); + + List getOneToOneAttributes(); + + List getManyToOneAttributes(); + + List getDiscriminatedAssociations(); + + List getElementCollectionAttributes(); + + List getOneToManyAttributes(); + + List getManyToManyAttributes(); + + List getPluralDiscriminatedAssociations(); + + List getTransients(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/CollectionAttribute.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/CollectionAttribute.java similarity index 77% rename from hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/CollectionAttribute.java rename to hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/CollectionAttribute.java index 8cf4df7e00..2ba6efc245 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/CollectionAttribute.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/CollectionAttribute.java @@ -2,20 +2,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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ -package org.hibernate.boot.jaxb.mapping.spi; +package org.hibernate.boot.jaxb.mapping; import java.util.List; + import jakarta.persistence.EnumType; import jakarta.persistence.TemporalType; /** - * Common interface for Jaxb bindings that represent persistent collection attributes. + * JAXB binding interface for plural attributes * * @author Brett Meyer */ public interface CollectionAttribute extends FetchableAttribute { + JaxbPluralFetchMode getFetchMode(); + + void setFetchMode(JaxbPluralFetchMode mode); String getOrderBy(); @@ -25,6 +29,10 @@ public interface CollectionAttribute extends FetchableAttribute { void setOrderColumn(JaxbOrderColumn value); + String getSort(); + + void setSort(String value); + JaxbMapKey getMapKey(); void setMapKey(JaxbMapKey value); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/DiscriminatedAssociation.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/DiscriminatedAssociation.java new file mode 100644 index 0000000000..cfcb930abc --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/DiscriminatedAssociation.java @@ -0,0 +1,52 @@ +/* + * 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.boot.jaxb.mapping; + +import java.util.List; + +/** + * JAXB binding interface for discriminated association based attributes (any and many-to-any) + * + * @author Steve Ebersole + */ +public interface DiscriminatedAssociation extends PersistentAttribute { + /** + * Details about the logical association foreign-key + */ + Key getKey(); + + /** + * Details about the discriminator + */ + Discriminator getDiscriminator(); + + /** + * The key of a {@link DiscriminatedAssociation} - the (logical) foreign-key value + * + * @author Steve Ebersole + */ + interface Key { + List getColumns(); + } + + /** + * JAXB binding interface for describing the discriminator of a discriminated association + * + * @author Steve Ebersole + */ + interface Discriminator { + /** + * The column holding the discriminator value + */ + JaxbColumn getColumn(); + + /** + * Mapping of discriminator-values to the corresponding entity names + */ + List getValueMappings(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/DiscriminatorMapping.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/DiscriminatorMapping.java new file mode 100644 index 0000000000..8b143e8d94 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/DiscriminatorMapping.java @@ -0,0 +1,17 @@ +/* + * 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.boot.jaxb.mapping; + +/** + * Mapping of a discriminator value to the corresponding entity-name + * + * @author Steve Ebersole + */ +public interface DiscriminatorMapping { + String getDiscriminatorValue(); + String getCorrespondingEntityName(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/EntityOrMappedSuperclass.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/EntityOrMappedSuperclass.java similarity index 83% rename from hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/EntityOrMappedSuperclass.java rename to hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/EntityOrMappedSuperclass.java index 0c33cec1ae..3dc612cbf7 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/EntityOrMappedSuperclass.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/EntityOrMappedSuperclass.java @@ -2,15 +2,16 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ -package org.hibernate.boot.jaxb.mapping.spi; +package org.hibernate.boot.jaxb.mapping; /** - * Common interface for JAXB bindings representing entities and mapped-superclasses. + * JAXB binding interface for commonality between entity and mapped-superclass mappings + * + * @author Steve Ebersole */ public interface EntityOrMappedSuperclass extends ManagedType, LifecycleCallbackContainer { - JaxbIdClass getIdClass(); void setIdClass(JaxbIdClass value); @@ -58,5 +59,4 @@ public interface EntityOrMappedSuperclass extends ManagedType, LifecycleCallback JaxbAttributes getAttributes(); void setAttributes(JaxbAttributes value); - } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/FetchableAttribute.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/FetchableAttribute.java new file mode 100644 index 0000000000..c4a72fb652 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/FetchableAttribute.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.boot.jaxb.mapping; + +import jakarta.persistence.FetchType; + +/** + * JAXB binding interface for EAGER/LAZY + * + * @apiNote All standard attributes are fetchable (basics allow FetchType as well); this + * contract distinguishes ANY mappings which are always eager and so do not allow + * specifying FetchType. + * + * @author Brett Meyer + * @author Steve Ebersole + */ +public interface FetchableAttribute extends PersistentAttribute { + FetchType getFetch(); + void setFetch(FetchType value); +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/LifecycleCallback.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/LifecycleCallback.java similarity index 54% rename from hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/LifecycleCallback.java rename to hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/LifecycleCallback.java index 223207dd81..32cf111758 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/LifecycleCallback.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/LifecycleCallback.java @@ -2,12 +2,12 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ -package org.hibernate.boot.jaxb.mapping.spi; +package org.hibernate.boot.jaxb.mapping; /** - * Common interface for all the JAXB bindings representing lifecycle callbacks. + * JAXB binding interface for lifecycle callbacks. * * @author Strong Liu * @author Steve Ebersole diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/LifecycleCallbackContainer.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/LifecycleCallbackContainer.java similarity index 67% rename from hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/LifecycleCallbackContainer.java rename to hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/LifecycleCallbackContainer.java index 7c0550491e..65d803b0c1 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/LifecycleCallbackContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/LifecycleCallbackContainer.java @@ -1,16 +1,25 @@ /* * 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 + * 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.boot.jaxb.mapping.spi; +package org.hibernate.boot.jaxb.mapping; +/** + * JAXB binding interface for commonality between things which + * allow callback declarations. This includes

    + *
  • + * entities and mapped-superclasses + *
  • + *
  • + * entity-listener classes + *
  • + *
+ * + * @author Steve Ebersole + */ public interface LifecycleCallbackContainer { - String getDescription(); - - void setDescription(String value); - JaxbPrePersist getPrePersist(); void setPrePersist(JaxbPrePersist value); @@ -38,8 +47,4 @@ public interface LifecycleCallbackContainer { JaxbPostLoad getPostLoad(); void setPostLoad(JaxbPostLoad value); - - String getClazz(); - - void setClazz(String value); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/ManagedType.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/ManagedType.java similarity index 84% rename from hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/ManagedType.java rename to hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/ManagedType.java index a2498e78ee..e4606f07c9 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/ManagedType.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/ManagedType.java @@ -2,9 +2,9 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ -package org.hibernate.boot.jaxb.mapping.spi; +package org.hibernate.boot.jaxb.mapping; import jakarta.persistence.AccessType; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/NamedQuery.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/NamedQuery.java similarity index 75% rename from hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/NamedQuery.java rename to hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/NamedQuery.java index 0345884f43..671fb98d25 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/NamedQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/NamedQuery.java @@ -1,31 +1,34 @@ /* * 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 + * 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.boot.jaxb.mapping.spi; +package org.hibernate.boot.jaxb.mapping; import java.io.Serializable; import java.util.List; + import jakarta.persistence.LockModeType; public interface NamedQuery extends Serializable { - String getDescription(); + String getName(); + void setName(String value); + String getDescription(); void setDescription(String value); String getQuery(); - void setQuery(String value); - LockModeType getLockMode(); + String getComment(); + void setComment(String comment); + Integer getTimeout(); + void setTimeout(Integer timeout); + + LockModeType getLockMode(); void setLockMode(LockModeType value); List getHint(); - - String getName(); - - void setName(String value); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/NaturalId.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/NaturalId.java new file mode 100644 index 0000000000..00636b8cb7 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/NaturalId.java @@ -0,0 +1,25 @@ +/* + * 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.boot.jaxb.mapping; + +import java.util.List; + +/** + * JAXB binding interface for natural-id definitions + * + * @author Steve Ebersole + */ +public interface NaturalId { + /** + * The cache config associated with this natural-id + */ + JaxbCaching getCaching(); + + List getBasicAttributes(); + + List getManyToOneAttributes(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/PersistentAttribute.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/PersistentAttribute.java similarity index 53% rename from hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/PersistentAttribute.java rename to hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/PersistentAttribute.java index bd879814d2..a786086899 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/PersistentAttribute.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/PersistentAttribute.java @@ -2,9 +2,9 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ -package org.hibernate.boot.jaxb.mapping.spi; +package org.hibernate.boot.jaxb.mapping; import jakarta.persistence.AccessType; @@ -15,9 +15,21 @@ import jakarta.persistence.AccessType; * @author Steve Ebersole */ public interface PersistentAttribute { + /** + * The attribute's name + */ String getName(); + void setName(String name); + /** + * JPA's way to specify an access-strategy + */ AccessType getAccess(); - void setAccess(AccessType accessType); + + /** + * Hibernate's pluggable access-strategy support + */ + String getAttributeAccessor(); + void setAttributeAccessor(String value); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/SchemaAware.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/SchemaAware.java similarity index 75% rename from hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/SchemaAware.java rename to hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/SchemaAware.java index 3f726a4b51..6c0d1c5759 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/SchemaAware.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/SchemaAware.java @@ -2,9 +2,9 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ -package org.hibernate.boot.jaxb.mapping.spi; +package org.hibernate.boot.jaxb.mapping; /** * Common interface for JAXB bindings that understand database schema (tables, sequences, etc). @@ -14,10 +14,8 @@ package org.hibernate.boot.jaxb.mapping.spi; */ public interface SchemaAware { String getSchema(); - void setSchema(String schema); String getCatalog(); - void setCatalog(String catalog); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/ToOneAttribute.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/ToOneAttribute.java new file mode 100644 index 0000000000..0c263bb433 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/ToOneAttribute.java @@ -0,0 +1,16 @@ +/* + * 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.boot.jaxb.mapping; + +/** + * @author Steve Ebersole + */ +public interface ToOneAttribute extends AssociationAttribute { + JaxbSingularFetchMode getFetchMode(); + + void setFetchMode(JaxbSingularFetchMode mode); +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/AccessTypeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/AccessTypeMarshalling.java similarity index 64% rename from hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/AccessTypeMarshalling.java rename to hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/AccessTypeMarshalling.java index 9795d689a5..21a93bab80 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/AccessTypeMarshalling.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/AccessTypeMarshalling.java @@ -2,14 +2,14 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ -package org.hibernate.boot.jaxb.mapping.internal; +package org.hibernate.boot.jaxb.mapping.marshall; import jakarta.persistence.AccessType; /** - * Marshalling support for dealing with JPA AccessType enums. Plugged into JAXB for binding + * JAXB marshalling for JPA's {@link AccessType} * * @author Steve Ebersole */ diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/CacheAccessTypeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/CacheAccessTypeMarshalling.java new file mode 100644 index 0000000000..1327781107 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/CacheAccessTypeMarshalling.java @@ -0,0 +1,25 @@ +/* + * 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.boot.jaxb.mapping.marshall; + +import org.hibernate.cache.spi.access.AccessType; + +/** + * JAXB marshalling for Hibernate's {@link AccessType} + * + * @author Steve Ebersole + */ +public class CacheAccessTypeMarshalling { + public static AccessType fromXml(String name) { + return AccessType.fromExternalName( name ); + } + + public static String toXml(AccessType accessType) { + return accessType.name(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/CacheModeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/CacheModeMarshalling.java new file mode 100644 index 0000000000..c48e2a4589 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/CacheModeMarshalling.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.boot.jaxb.mapping.marshall; + +import java.util.Locale; + +import org.hibernate.CacheMode; + +/** + * JAXB marshalling for Hibernate's {@link CacheMode} + * + * @author Steve Ebersole + */ +public class CacheModeMarshalling { + public static CacheMode fromXml(String name) { + for ( CacheMode mode : CacheMode.values() ) { + if ( mode.name().equalsIgnoreCase( name ) ) { + return mode; + } + } + return CacheMode.NORMAL; + } + + public static String toXml(CacheMode cacheMode) { + return cacheMode.name().toLowerCase( Locale.ENGLISH ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/ConstraintModeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/ConstraintModeMarshalling.java similarity index 65% rename from hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/ConstraintModeMarshalling.java rename to hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/ConstraintModeMarshalling.java index 0fdfea728a..d6830a8351 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/ConstraintModeMarshalling.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/ConstraintModeMarshalling.java @@ -2,14 +2,14 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ -package org.hibernate.boot.jaxb.mapping.internal; +package org.hibernate.boot.jaxb.mapping.marshall; import jakarta.persistence.ConstraintMode; /** - * Marshalling support for dealing with JPA ConstraintMode enums. Plugged into JAXB for binding + * JAXB marshalling for JPA's {@link ConstraintMode} * * @author Steve Ebersole */ diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/DiscriminatorTypeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/DiscriminatorTypeMarshalling.java similarity index 66% rename from hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/DiscriminatorTypeMarshalling.java rename to hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/DiscriminatorTypeMarshalling.java index 7e83f88b57..cecce8faf9 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/DiscriminatorTypeMarshalling.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/DiscriminatorTypeMarshalling.java @@ -2,14 +2,14 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ -package org.hibernate.boot.jaxb.mapping.internal; +package org.hibernate.boot.jaxb.mapping.marshall; import jakarta.persistence.DiscriminatorType; /** - * Marshalling support for dealing with JPA DiscriminatorType enums. Plugged into JAXB for binding + * JAXB marshalling for {@link DiscriminatorType} * * @author Steve Ebersole */ diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/EnumTypeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/EnumTypeMarshalling.java similarity index 63% rename from hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/EnumTypeMarshalling.java rename to hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/EnumTypeMarshalling.java index e0784744ac..4abd0232e1 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/EnumTypeMarshalling.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/EnumTypeMarshalling.java @@ -2,14 +2,14 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ -package org.hibernate.boot.jaxb.mapping.internal; +package org.hibernate.boot.jaxb.mapping.marshall; import jakarta.persistence.EnumType; /** - * Marshalling support for dealing with JPA EnumType enums. Plugged into JAXB for binding + * JAXB marshalling for {@link EnumType} * * @author Steve Ebersole */ diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/FetchTypeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/FetchTypeMarshalling.java similarity index 64% rename from hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/FetchTypeMarshalling.java rename to hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/FetchTypeMarshalling.java index d4415f9ea1..282ae23550 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/FetchTypeMarshalling.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/FetchTypeMarshalling.java @@ -2,14 +2,14 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ -package org.hibernate.boot.jaxb.mapping.internal; +package org.hibernate.boot.jaxb.mapping.marshall; import jakarta.persistence.FetchType; /** - * Marshalling support for dealing with JPA FetchType enums. Plugged into JAXB for binding + * JAXB marshalling for {@link FetchType} * * @author Steve Ebersole */ diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/FlushModeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/FlushModeMarshalling.java new file mode 100644 index 0000000000..45e54fe492 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/FlushModeMarshalling.java @@ -0,0 +1,63 @@ +/* + * 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.boot.jaxb.mapping.marshall; + +import java.util.Locale; + +import org.hibernate.FlushMode; +import org.hibernate.HibernateException; + +/** + * JAXB marshalling for {@link FlushMode} + *

+ * NOTE : The XML schemas define the use of {@code "never"}, which corresponds + * to the removed FlushMode#NEVER. Here we will also handle mapping + * FlushMode#NEVER to FlushMode#MANUAL + * + * @author Steve Ebersole + */ +public class FlushModeMarshalling { + public static FlushMode fromXml(String name) { + // valid values are a subset of all FlushMode possibilities, so we will + // handle the conversion here directly. + // Also, we want to map "never"->MANUAL (rather than NEVER) + if ( name == null ) { + return null; + } + + if ( "never".equalsIgnoreCase( name ) ) { + return FlushMode.MANUAL; + } + else if ( "auto".equalsIgnoreCase( name ) ) { + return FlushMode.AUTO; + } + else if ( "always".equalsIgnoreCase( name ) ) { + return FlushMode.ALWAYS; + } + + // if the incoming value was not null *and* was not one of the pre-defined + // values, we need to throw an exception. This *should never happen if the + // document we are processing conforms to the schema... + throw new HibernateException( "Unrecognized flush mode : " + name ); + } + + public static String toXml(FlushMode mode) { + if ( mode == null ) { + return null; + } + + // conversely, we want to map MANUAL -> "never" here + if ( mode == FlushMode.MANUAL ) { + return "never"; + } + + // todo : what to do if the incoming value does not conform to allowed values? + // for now, we simply don't deal with that (we write it out). + + return mode.name().toLowerCase( Locale.ENGLISH ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/GenerationTimingMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/GenerationTimingMarshalling.java new file mode 100644 index 0000000000..92a1c4865f --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/GenerationTimingMarshalling.java @@ -0,0 +1,28 @@ +/* + * 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.boot.jaxb.mapping.marshall; + +import java.util.Locale; + +import org.hibernate.tuple.GenerationTiming; + +/** + * JAXB marshalling for {@link GenerationTiming} + * + * @author Steve Ebersole + */ +public class GenerationTimingMarshalling { + public static GenerationTiming fromXml(String name) { + return GenerationTiming.parseFromName( name ); + } + + public static String toXml(GenerationTiming generationTiming) { + return ( null == generationTiming ) ? + null : + generationTiming.name().toLowerCase( Locale.ENGLISH ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/GenerationTypeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/GenerationTypeMarshalling.java similarity index 65% rename from hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/GenerationTypeMarshalling.java rename to hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/GenerationTypeMarshalling.java index a2c4308f36..4a29d0e020 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/GenerationTypeMarshalling.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/GenerationTypeMarshalling.java @@ -2,14 +2,14 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ -package org.hibernate.boot.jaxb.mapping.internal; +package org.hibernate.boot.jaxb.mapping.marshall; import jakarta.persistence.GenerationType; /** - * Marshalling support for dealing with JPA GenerationType enums. Plugged into JAXB for binding + * JAXB marshalling for {@link GenerationType} * * @author Steve Ebersole */ diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/InheritanceTypeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/InheritanceTypeMarshalling.java similarity index 65% rename from hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/InheritanceTypeMarshalling.java rename to hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/InheritanceTypeMarshalling.java index 22ad54e650..5c12443337 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/InheritanceTypeMarshalling.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/InheritanceTypeMarshalling.java @@ -2,14 +2,14 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ -package org.hibernate.boot.jaxb.mapping.internal; +package org.hibernate.boot.jaxb.mapping.marshall; import jakarta.persistence.InheritanceType; /** - * Marshalling support for dealing with JPA InheritanceType enums. Plugged into JAXB for binding + * JAXB marshalling for {@link InheritanceType} * * @author Steve Ebersole */ diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/LockModeTypeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/LockModeTypeMarshalling.java similarity index 65% rename from hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/LockModeTypeMarshalling.java rename to hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/LockModeTypeMarshalling.java index 2990e96d53..35fcae534a 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/LockModeTypeMarshalling.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/LockModeTypeMarshalling.java @@ -2,14 +2,14 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ -package org.hibernate.boot.jaxb.mapping.internal; +package org.hibernate.boot.jaxb.mapping.marshall; import jakarta.persistence.LockModeType; /** - * Marshalling support for dealing with JPA LockModeType enums. Plugged into JAXB for binding + * JAXB marshalling for {@link LockModeType} * * @author Steve Ebersole */ diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/OnDeleteActionMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/OnDeleteActionMarshalling.java new file mode 100644 index 0000000000..8e2806f659 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/OnDeleteActionMarshalling.java @@ -0,0 +1,22 @@ +/* + * 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.boot.jaxb.mapping.marshall; + +import org.hibernate.annotations.OnDeleteAction; + +/** + * @author Steve Ebersole + */ +public class OnDeleteActionMarshalling { + public static OnDeleteAction fromXml(String name) { + return OnDeleteAction.fromExternalForm( name ); + } + + public static String toXml(OnDeleteAction accessType) { + return accessType.getAlternativeName(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/OptimisticLockStyleMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/OptimisticLockStyleMarshalling.java new file mode 100644 index 0000000000..2a8f0cde2b --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/OptimisticLockStyleMarshalling.java @@ -0,0 +1,26 @@ +/* + * 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.boot.jaxb.mapping.marshall; + +import java.util.Locale; + +import org.hibernate.engine.OptimisticLockStyle; + +/** + * JAXB marshalling for {@link OptimisticLockStyle} + * + * @author Steve Ebersole + */ +public class OptimisticLockStyleMarshalling { + public static OptimisticLockStyle fromXml(String name) { + return OptimisticLockStyle.valueOf( name == null ? null : name.toUpperCase( Locale.ENGLISH ) ); + } + + public static String toXml(OptimisticLockStyle lockMode) { + return lockMode == null ? null : lockMode.name().toLowerCase( Locale.ENGLISH ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/ParameterModeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/ParameterModeMarshalling.java similarity index 65% rename from hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/ParameterModeMarshalling.java rename to hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/ParameterModeMarshalling.java index f4389454a6..2e115756b9 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/ParameterModeMarshalling.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/ParameterModeMarshalling.java @@ -2,14 +2,14 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ -package org.hibernate.boot.jaxb.mapping.internal; +package org.hibernate.boot.jaxb.mapping.marshall; import jakarta.persistence.ParameterMode; /** - * Marshalling support for dealing with JPA ParameterMode enums. Plugged into JAXB for binding + * JAXB marshalling for {@link ParameterMode} * * @author Steve Ebersole */ diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/PolymorphismTypeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/PolymorphismTypeMarshalling.java new file mode 100644 index 0000000000..35883f737b --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/PolymorphismTypeMarshalling.java @@ -0,0 +1,22 @@ +/* + * 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.boot.jaxb.mapping.marshall; + +import org.hibernate.annotations.PolymorphismType; + +/** + * @author Steve Ebersole + */ +public class PolymorphismTypeMarshalling { + public static PolymorphismType fromXml(String value) { + return PolymorphismType.fromExternalValue( value ); + } + + public static String toXml(PolymorphismType value) { + return value.getExternalForm(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/ResultCheckStyleMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/ResultCheckStyleMarshalling.java new file mode 100644 index 0000000000..55526424b8 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/ResultCheckStyleMarshalling.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.boot.jaxb.mapping.marshall; + +import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle; + +/** + * JAXB marshalling for {@link ExecuteUpdateResultCheckStyle} + * + * @author Steve Ebersole + */ +public class ResultCheckStyleMarshalling { + public static ExecuteUpdateResultCheckStyle fromXml(String name) { + return ExecuteUpdateResultCheckStyle.fromExternalName( name ); + } + + public static String toXml(ExecuteUpdateResultCheckStyle style) { + return style.externalName(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/TemporalTypeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/TemporalTypeMarshalling.java similarity index 65% rename from hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/TemporalTypeMarshalling.java rename to hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/TemporalTypeMarshalling.java index fb23ff6842..77ad2fc8b9 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/TemporalTypeMarshalling.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/marshall/TemporalTypeMarshalling.java @@ -2,14 +2,14 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ -package org.hibernate.boot.jaxb.mapping.internal; +package org.hibernate.boot.jaxb.mapping.marshall; import jakarta.persistence.TemporalType; /** - * Marshalling support for dealing with JPA TemporalType enums. Plugged into JAXB for binding + * JAXB marshalling for {@link TemporalType} * * @author Steve Ebersole */ diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/package-info.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/package-info.java deleted file mode 100644 index 0d61b3224e..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/package-info.java +++ /dev/null @@ -1,11 +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 . - */ - -/** - * JAXB for JPA's {@code orm.xml} mapping schema. - */ -package org.hibernate.boot.jaxb.mapping; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/AttributesContainer.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/AttributesContainer.java deleted file mode 100644 index 18b20d6592..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/AttributesContainer.java +++ /dev/null @@ -1,35 +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 . - */ -package org.hibernate.boot.jaxb.mapping.spi; - -import java.util.List; - -/** - * Common interface for JAXB bindings which are containers of attributes. - * - * @author Strong Liu - * @author Steve Ebersole - */ -public interface AttributesContainer { - - List getTransient(); - - List getBasic(); - - List getElementCollection(); - - List getEmbedded(); - - List getManyToMany(); - - List getManyToOne(); - - List getOneToMany(); - - List getOneToOne(); - -} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/FetchableAttribute.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/FetchableAttribute.java deleted file mode 100644 index 03ce9ef0b8..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/FetchableAttribute.java +++ /dev/null @@ -1,22 +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 . - */ -package org.hibernate.boot.jaxb.mapping.spi; - -import jakarta.persistence.FetchType; - -/** - * Common interface for JAXB bindings that represent attributes with laziness and fetch style. - * - * @author Brett Meyer - */ -public interface FetchableAttribute { - - FetchType getFetch(); - - void setFetch(FetchType value); - -} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/spi/BindableMappingDescriptor.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/spi/BindableMappingDescriptor.java new file mode 100644 index 0000000000..5a2c489ed4 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/spi/BindableMappingDescriptor.java @@ -0,0 +1,19 @@ +/* + * 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.boot.jaxb.spi; + +/** + * Common type for things that can get be bound to a {@link Binding} for + * mapping documents. + * + * @apiNote The models generated from the hbm.xml and mapping.xml schemas + * both implement it. + * + * @author Steve Ebersole + */ +public interface BindableMappingDescriptor { +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/spi/Binder.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/spi/Binder.java index c6327ea003..6e27b12e85 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/spi/Binder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/spi/Binder.java @@ -2,7 +2,7 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ package org.hibernate.boot.jaxb.spi; @@ -16,24 +16,22 @@ import org.hibernate.boot.jaxb.Origin; * * @author Steve Ebersole */ -public interface Binder { +public interface Binder { /** * Bind from an XML source. * * @param source The XML source. * @param origin The descriptor of the source origin - * * @return The bound JAXB model */ - Binding bind(Source source, Origin origin); + Binding bind(Source source, Origin origin); /** * Bind from an InputStream * * @param stream The InputStream containing XML * @param origin The descriptor of the stream origin - * * @return The bound JAXB model */ - Binding bind(InputStream stream, Origin origin); + Binding bind(InputStream stream, Origin origin); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/process/spi/MetadataBuildingProcess.java b/hibernate-core/src/main/java/org/hibernate/boot/model/process/spi/MetadataBuildingProcess.java index 53cd0d8e4a..3c168f0cf4 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/process/spi/MetadataBuildingProcess.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/process/spi/MetadataBuildingProcess.java @@ -15,7 +15,6 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import org.hibernate.TimeZoneStorageStrategy; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.internal.InFlightMetadataCollectorImpl; import org.hibernate.boot.internal.MetadataBuildingContextRootImpl; @@ -306,12 +305,25 @@ public class MetadataBuildingProcess { processor.finishUp(); if ( options.isXmlMappingEnabled() ) { + //noinspection deprecation final Iterable producers = classLoaderService.loadJavaServices( AdditionalJaxbMappingProducer.class ); if ( producers != null ) { final EntityHierarchyBuilder hierarchyBuilder = new EntityHierarchyBuilder(); - // final MappingBinder mappingBinder = new MappingBinder( true ); - // We need to disable validation here. It seems Envers is not producing valid (according to schema) XML - final MappingBinder mappingBinder = new MappingBinder( classLoaderService, false ); + final MappingBinder mappingBinder = new MappingBinder( + classLoaderService, + new MappingBinder.Options() { + @Override + public boolean validateMappings() { + return false; + } + + @Override + public boolean transformHbmMappings() { + return false; + } + } + ); + //noinspection deprecation for ( AdditionalJaxbMappingProducer producer : producers ) { log.tracef( "Calling AdditionalJaxbMappingProducer : %s", producer ); Collection additionalMappings = producer.produceAdditionalMappings( diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java index f36350e28d..fac77e7ee6 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java @@ -2,7 +2,7 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ package org.hibernate.boot.model.source.internal.annotations; @@ -11,18 +11,13 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; -import jakarta.persistence.AttributeConverter; -import jakarta.persistence.Converter; -import jakarta.persistence.Embeddable; -import jakarta.persistence.Entity; -import jakarta.persistence.MappedSuperclass; import org.hibernate.annotations.common.reflection.MetadataProviderInjector; import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.boot.AttributeConverterInfo; import org.hibernate.boot.internal.MetadataBuildingContextRootImpl; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; +import org.hibernate.boot.jaxb.mapping.JaxbEntityMappings; import org.hibernate.boot.jaxb.spi.Binding; import org.hibernate.boot.model.convert.spi.ConverterDescriptor; import org.hibernate.boot.model.process.spi.ManagedResources; @@ -41,6 +36,12 @@ import org.hibernate.internal.util.collections.CollectionHelper; import org.jboss.jandex.IndexView; import org.jboss.logging.Logger; +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; +import jakarta.persistence.Embeddable; +import jakarta.persistence.Entity; +import jakarta.persistence.MappedSuperclass; + /** * @author Steve Ebersole */ @@ -83,10 +84,10 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc ( (MetadataProviderInjector) reflectionManager ).getMetadataProvider(); for ( Binding xmlBinding : managedResources.getXmlMappingBindings() ) { Object root = xmlBinding.getRoot(); - if ( !(root instanceof JaxbEntityMappings) ) { + if ( !( root instanceof JaxbEntityMappings ) ) { continue; } - JaxbEntityMappings entityMappings = (JaxbEntityMappings) xmlBinding.getRoot(); + final JaxbEntityMappings entityMappings = (JaxbEntityMappings) xmlBinding.getRoot(); final List classNames = jpaMetadataProvider.getXMLContext().addDocument( entityMappings ); for ( String className : classNames ) { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/registry/classloading/spi/ClassLoaderService.java b/hibernate-core/src/main/java/org/hibernate/boot/registry/classloading/spi/ClassLoaderService.java index 485aca1b14..21c8782ac2 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/registry/classloading/spi/ClassLoaderService.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/registry/classloading/spi/ClassLoaderService.java @@ -2,7 +2,7 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ package org.hibernate.boot.registry.classloading.spi; @@ -12,6 +12,8 @@ import java.net.URL; import java.util.Collection; import java.util.List; +import org.hibernate.boot.ResourceLocator; +import org.hibernate.boot.ResourceStreamLocator; import org.hibernate.service.Service; import org.hibernate.service.spi.Stoppable; @@ -20,7 +22,7 @@ import org.hibernate.service.spi.Stoppable; * * @author Steve Ebersole */ -public interface ClassLoaderService extends Service, Stoppable { +public interface ClassLoaderService extends ResourceLocator, ResourceStreamLocator, Service, Stoppable { /** * Locate a class by name. * diff --git a/hibernate-core/src/main/java/org/hibernate/boot/registry/internal/BootstrapServiceRegistryImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/registry/internal/BootstrapServiceRegistryImpl.java index f641e71949..71fb3cbb95 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/registry/internal/BootstrapServiceRegistryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/registry/internal/BootstrapServiceRegistryImpl.java @@ -22,6 +22,7 @@ import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.service.Service; import org.hibernate.service.ServiceRegistry; +import org.hibernate.service.internal.AbstractServiceRegistryImpl; import org.hibernate.service.spi.ServiceBinding; import org.hibernate.service.spi.ServiceException; import org.hibernate.service.spi.ServiceInitiator; @@ -306,4 +307,9 @@ public class BootstrapServiceRegistryImpl } } } + + @Override + public T fromRegistryOrChildren(Class serviceRole) { + return AbstractServiceRegistryImpl.fromRegistryOrChildren( serviceRole, this, childRegistries ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/XmlMappingBinderAccess.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/XmlMappingBinderAccess.java index 5bd5e56173..f0134277c2 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/XmlMappingBinderAccess.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/XmlMappingBinderAccess.java @@ -10,6 +10,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.util.function.Function; import org.hibernate.boot.MappingNotFoundException; import org.hibernate.boot.archive.spi.InputStreamAccess; @@ -19,6 +20,7 @@ import org.hibernate.boot.jaxb.internal.FileXmlSource; import org.hibernate.boot.jaxb.internal.InputStreamXmlSource; import org.hibernate.boot.jaxb.internal.MappingBinder; import org.hibernate.boot.jaxb.internal.UrlXmlSource; +import org.hibernate.boot.jaxb.spi.BindableMappingDescriptor; import org.hibernate.boot.jaxb.spi.Binding; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.service.ServiceRegistry; @@ -26,6 +28,9 @@ import org.hibernate.service.ServiceRegistry; import org.jboss.logging.Logger; /** + * Poor naming. Models the binder and a class-loader to be a + * one-stop-shop in terms of {@link #bind binding} a resource + * * @author Steve Ebersole */ public class XmlMappingBinderAccess { @@ -36,18 +41,19 @@ public class XmlMappingBinderAccess { public XmlMappingBinderAccess(ServiceRegistry serviceRegistry) { this.classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); + this.mappingBinder = new MappingBinder( serviceRegistry ); + } - // NOTE : The boolean here indicates whether or not to perform validation as we load XML documents. - // Should we expose this setting? Disabling would speed up JAXP and JAXB at runtime, but potentially - // at the cost of less obvious errors when a document is not valid. - this.mappingBinder = new MappingBinder( classLoaderService, true ); + public XmlMappingBinderAccess(ServiceRegistry serviceRegistry, Function configAccess) { + this.classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); + this.mappingBinder = new MappingBinder( classLoaderService, configAccess ); } public MappingBinder getMappingBinder() { return mappingBinder; } - public Binding bind(String resource) { + public Binding bind(String resource) { LOG.tracef( "reading mappings from resource : %s", resource ); final Origin origin = new Origin( SourceType.RESOURCE, resource ); @@ -56,10 +62,11 @@ public class XmlMappingBinderAccess { throw new MappingNotFoundException( origin ); } + //noinspection unchecked return new UrlXmlSource( origin, url ).doBind( getMappingBinder() ); } - public Binding bind(File file) { + public Binding bind(File file) { final Origin origin = new Origin( SourceType.FILE, file.getPath() ); LOG.tracef( "reading mappings from file : %s", origin.getName() ); @@ -67,15 +74,17 @@ public class XmlMappingBinderAccess { throw new MappingNotFoundException( origin ); } + //noinspection unchecked return new FileXmlSource( origin, file ).doBind( getMappingBinder() ); } - public Binding bind(InputStreamAccess xmlInputStreamAccess) { + public Binding bind(InputStreamAccess xmlInputStreamAccess) { LOG.tracef( "reading mappings from InputStreamAccess : %s", xmlInputStreamAccess.getStreamName() ); final Origin origin = new Origin( SourceType.INPUT_STREAM, xmlInputStreamAccess.getStreamName() ); InputStream xmlInputStream = xmlInputStreamAccess.accessInputStream(); try { + //noinspection unchecked return new InputStreamXmlSource( origin, xmlInputStream, false ).doBind( mappingBinder ); } finally { @@ -88,17 +97,19 @@ public class XmlMappingBinderAccess { } } - public Binding bind(InputStream xmlInputStream) { + public Binding bind(InputStream xmlInputStream) { LOG.trace( "reading mappings from InputStream" ); final Origin origin = new Origin( SourceType.INPUT_STREAM, null ); + //noinspection unchecked return new InputStreamXmlSource( origin, xmlInputStream, false ).doBind( getMappingBinder() ); } - public Binding bind(URL url) { + public Binding bind(URL url) { final String urlExternalForm = url.toExternalForm(); LOG.debugf( "Reading mapping document from URL : %s", urlExternalForm ); final Origin origin = new Origin( SourceType.URL, urlExternalForm ); + //noinspection unchecked return new UrlXmlSource( origin, url ).doBind( getMappingBinder() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/xsd/MappingXsdSupport.java b/hibernate-core/src/main/java/org/hibernate/boot/xsd/MappingXsdSupport.java index 93127b0d14..384fe119e8 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/xsd/MappingXsdSupport.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/xsd/MappingXsdSupport.java @@ -1,8 +1,8 @@ /* * 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 + * 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.boot.xsd; @@ -23,6 +23,12 @@ public class MappingXsdSupport { */ public static final MappingXsdSupport INSTANCE = new MappingXsdSupport(); + public static final XsdDescriptor _310 = LocalXsdResolver.buildXsdDescriptor( + "org/hibernate/xsd/mapping/mapping-3.1.0.xsd", + "3.1", + "http://www.hibernate.org/xsd/orm/mapping" + ); + public static final XsdDescriptor jpa10 = LocalXsdResolver.buildXsdDescriptor( "org/hibernate/jpa/orm_1_0.xsd", "1.0", @@ -75,6 +81,10 @@ public class MappingXsdSupport { //Do not construct new instances } + public static XsdDescriptor latestDescriptor() { + return _310; + } + public static XsdDescriptor latestJpaDescriptor() { return jpa22; } diff --git a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/AccessType.java b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/AccessType.java index ae1b4a55c8..797237f660 100644 --- a/hibernate-core/src/main/java/org/hibernate/cache/spi/access/AccessType.java +++ b/hibernate-core/src/main/java/org/hibernate/cache/spi/access/AccessType.java @@ -2,7 +2,7 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ package org.hibernate.cache.spi.access; @@ -75,7 +75,7 @@ public enum AccessType { } // Check to see if making upper-case matches an enum name. try { - return AccessType.valueOf( externalName.toUpperCase( Locale.ROOT) ); + return AccessType.valueOf( externalName.toUpperCase( Locale.ROOT ) ); } catch ( IllegalArgumentException e ) { throw new UnknownAccessTypeException( externalName ); diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index 2181d63315..c79ac70884 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -2,29 +2,30 @@ * Hibernate, Relational Persistence for Idiomatic Java * * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ package org.hibernate.cfg; import java.util.function.Supplier; -import jakarta.persistence.criteria.CriteriaDelete; -import jakarta.persistence.criteria.CriteriaQuery; -import jakarta.persistence.criteria.CriteriaUpdate; import org.hibernate.CustomEntityDirtinessStrategy; import org.hibernate.Incubating; import org.hibernate.Interceptor; import org.hibernate.SessionFactoryObserver; import org.hibernate.boot.registry.selector.spi.StrategySelector; -import org.hibernate.id.enhanced.ImplicitDatabaseObjectNamingStrategy; import org.hibernate.cache.spi.TimestampsCacheFactory; import org.hibernate.context.spi.CurrentTenantIdentifierResolver; +import org.hibernate.id.enhanced.ImplicitDatabaseObjectNamingStrategy; import org.hibernate.jpa.LegacySpecHints; import org.hibernate.query.spi.QueryPlan; import org.hibernate.query.sqm.NullPrecedence; import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; import org.hibernate.resource.jdbc.spi.StatementInspector; +import jakarta.persistence.criteria.CriteriaDelete; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.CriteriaUpdate; + /** * Enumerates the configuration properties supported by Hibernate, including * properties defined by the JPA specification. @@ -2934,4 +2935,31 @@ public interface AvailableSettings { * By default, the persistent context is not discarded, as per the JPA specification. */ String DISCARD_PC_ON_CLOSE = "hibernate.discard_pc_on_close"; + + /** + * Whether XML should be validated against their schema as Hibernate reads them. + *

+ * Default is {@code true} + * + * @since 6.1 + */ + String VALIDATE_XML = "hibernate.validate_xml"; + + /** + * Enables processing `hbm.xml` mappings by transforming them to `mapping.xml` and using + * that processor. Default is false, must be opted-into. + * + * @since 6.1 + */ + String TRANSFORM_HBM_XML = "hibernate.transform_hbm_xml.enabled"; + + /** + * How features in a `hbm.xml` file which are not supported for transformation should be handled. + *

+ * Default is {@link org.hibernate.boot.jaxb.hbm.transform.UnsupportedFeatureHandling#ERROR} + * + * @see org.hibernate.boot.jaxb.hbm.transform.UnsupportedFeatureHandling + * @since 6.1 + */ + String TRANSFORM_HBM_XML_FEATURE_HANDLING = "hibernate.transform_hbm_xml.unsupported_feature_handling"; } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java b/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java index fc1d0da859..722f4598fd 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java @@ -15,8 +15,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; -import jakarta.persistence.AttributeConverter; -import jakarta.persistence.SharedCacheMode; import org.hibernate.EmptyInterceptor; import org.hibernate.HibernateException; @@ -39,14 +37,14 @@ import org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl; import org.hibernate.boot.model.naming.PhysicalNamingStrategy; import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl; import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject; -import org.hibernate.boot.registry.BootstrapServiceRegistry; -import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.boot.query.NamedHqlQueryDefinition; import org.hibernate.boot.query.NamedNativeQueryDefinition; import org.hibernate.boot.query.NamedProcedureCallDefinition; import org.hibernate.boot.query.NamedResultSetMappingDescriptor; +import org.hibernate.boot.registry.BootstrapServiceRegistry; +import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.boot.spi.XmlMappingBinderAccess; import org.hibernate.cfg.annotations.NamedEntityGraphDefinition; import org.hibernate.context.spi.CurrentTenantIdentifierResolver; @@ -59,6 +57,9 @@ import org.hibernate.type.BasicType; import org.hibernate.type.SerializationException; import org.hibernate.usertype.UserType; +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.SharedCacheMode; + /** * A convenience API making it easier to bootstrap an instance of Hibernate * using {@link MetadataBuilder} and {@link StandardServiceRegistryBuilder} @@ -151,11 +152,18 @@ public class Configuration { */ public Configuration(BootstrapServiceRegistry serviceRegistry) { this.bootstrapServiceRegistry = serviceRegistry; - this.metadataSources = new MetadataSources( serviceRegistry ); + this.metadataSources = new MetadataSources( serviceRegistry, createMappingBinderAccess( serviceRegistry ) ); this.classmateContext = new ClassmateContext(); reset(); } + private XmlMappingBinderAccess createMappingBinderAccess(BootstrapServiceRegistry serviceRegistry) { + return new XmlMappingBinderAccess( + serviceRegistry, + (settingName) -> properties == null ? null : properties.get( settingName ) + ); + } + /** * Create a new instance, using the given {@link MetadataSources}, and a * {@link BootstrapServiceRegistry} obtained from the {@link MetadataSources}. diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java index 1c25c84510..74456c0a56 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java @@ -2,7 +2,7 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ package org.hibernate.cfg.annotations.reflection.internal; @@ -21,6 +21,88 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Function; + +import org.hibernate.AnnotationException; +import org.hibernate.annotations.Any; +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; +import org.hibernate.annotations.Cascade; +import org.hibernate.annotations.Columns; +import org.hibernate.annotations.ManyToAny; +import org.hibernate.annotations.Subselect; +import org.hibernate.annotations.common.annotationfactory.AnnotationDescriptor; +import org.hibernate.annotations.common.annotationfactory.AnnotationFactory; +import org.hibernate.annotations.common.reflection.AnnotationReader; +import org.hibernate.annotations.common.reflection.ReflectionUtil; +import org.hibernate.boot.jaxb.mapping.AssociationAttribute; +import org.hibernate.boot.jaxb.mapping.AttributesContainer; +import org.hibernate.boot.jaxb.mapping.EntityOrMappedSuperclass; +import org.hibernate.boot.jaxb.mapping.JaxbAssociationOverride; +import org.hibernate.boot.jaxb.mapping.JaxbAttributeOverride; +import org.hibernate.boot.jaxb.mapping.JaxbAttributes; +import org.hibernate.boot.jaxb.mapping.JaxbBasic; +import org.hibernate.boot.jaxb.mapping.JaxbCaching; +import org.hibernate.boot.jaxb.mapping.JaxbCascadeType; +import org.hibernate.boot.jaxb.mapping.JaxbCollectionTable; +import org.hibernate.boot.jaxb.mapping.JaxbColumn; +import org.hibernate.boot.jaxb.mapping.JaxbColumnResult; +import org.hibernate.boot.jaxb.mapping.JaxbConstructorResult; +import org.hibernate.boot.jaxb.mapping.JaxbConvert; +import org.hibernate.boot.jaxb.mapping.JaxbDiscriminatorColumn; +import org.hibernate.boot.jaxb.mapping.JaxbElementCollection; +import org.hibernate.boot.jaxb.mapping.JaxbEmbeddable; +import org.hibernate.boot.jaxb.mapping.JaxbEmbedded; +import org.hibernate.boot.jaxb.mapping.JaxbEmbeddedId; +import org.hibernate.boot.jaxb.mapping.JaxbEmptyType; +import org.hibernate.boot.jaxb.mapping.JaxbEntity; +import org.hibernate.boot.jaxb.mapping.JaxbEntityListener; +import org.hibernate.boot.jaxb.mapping.JaxbEntityListeners; +import org.hibernate.boot.jaxb.mapping.JaxbEntityResult; +import org.hibernate.boot.jaxb.mapping.JaxbFieldResult; +import org.hibernate.boot.jaxb.mapping.JaxbGeneratedValue; +import org.hibernate.boot.jaxb.mapping.JaxbId; +import org.hibernate.boot.jaxb.mapping.JaxbIdClass; +import org.hibernate.boot.jaxb.mapping.JaxbIndex; +import org.hibernate.boot.jaxb.mapping.JaxbInheritance; +import org.hibernate.boot.jaxb.mapping.JaxbJoinColumn; +import org.hibernate.boot.jaxb.mapping.JaxbJoinTable; +import org.hibernate.boot.jaxb.mapping.JaxbLob; +import org.hibernate.boot.jaxb.mapping.JaxbManyToMany; +import org.hibernate.boot.jaxb.mapping.JaxbManyToOne; +import org.hibernate.boot.jaxb.mapping.JaxbMapKey; +import org.hibernate.boot.jaxb.mapping.JaxbMapKeyClass; +import org.hibernate.boot.jaxb.mapping.JaxbMapKeyColumn; +import org.hibernate.boot.jaxb.mapping.JaxbMapKeyJoinColumn; +import org.hibernate.boot.jaxb.mapping.JaxbMappedSuperclass; +import org.hibernate.boot.jaxb.mapping.JaxbNamedAttributeNode; +import org.hibernate.boot.jaxb.mapping.JaxbNamedEntityGraph; +import org.hibernate.boot.jaxb.mapping.JaxbNamedNativeQuery; +import org.hibernate.boot.jaxb.mapping.JaxbNamedQuery; +import org.hibernate.boot.jaxb.mapping.JaxbNamedStoredProcedureQuery; +import org.hibernate.boot.jaxb.mapping.JaxbNamedSubgraph; +import org.hibernate.boot.jaxb.mapping.JaxbOneToMany; +import org.hibernate.boot.jaxb.mapping.JaxbOneToOne; +import org.hibernate.boot.jaxb.mapping.JaxbOrderColumn; +import org.hibernate.boot.jaxb.mapping.JaxbPrimaryKeyJoinColumn; +import org.hibernate.boot.jaxb.mapping.JaxbQueryHint; +import org.hibernate.boot.jaxb.mapping.JaxbSecondaryTable; +import org.hibernate.boot.jaxb.mapping.JaxbSequenceGenerator; +import org.hibernate.boot.jaxb.mapping.JaxbSqlResultSetMapping; +import org.hibernate.boot.jaxb.mapping.JaxbStoredProcedureParameter; +import org.hibernate.boot.jaxb.mapping.JaxbTable; +import org.hibernate.boot.jaxb.mapping.JaxbTableGenerator; +import org.hibernate.boot.jaxb.mapping.JaxbUniqueConstraint; +import org.hibernate.boot.jaxb.mapping.JaxbVersion; +import org.hibernate.boot.jaxb.mapping.LifecycleCallbackContainer; +import org.hibernate.boot.jaxb.mapping.ManagedType; +import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; +import org.hibernate.boot.spi.BootstrapContext; +import org.hibernate.boot.spi.ClassLoaderAccess; +import org.hibernate.cfg.annotations.reflection.PersistentAttributeFilter; +import org.hibernate.internal.CoreLogging; +import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.util.StringHelper; + import jakarta.persistence.Access; import jakarta.persistence.AccessType; import jakarta.persistence.AssociationOverride; @@ -114,84 +196,6 @@ import jakarta.persistence.Transient; import jakarta.persistence.UniqueConstraint; import jakarta.persistence.Version; -import org.hibernate.AnnotationException; -import org.hibernate.annotations.Any; -import org.hibernate.annotations.Cascade; -import org.hibernate.annotations.Columns; -import org.hibernate.annotations.ManyToAny; -import org.hibernate.annotations.common.annotationfactory.AnnotationDescriptor; -import org.hibernate.annotations.common.annotationfactory.AnnotationFactory; -import org.hibernate.annotations.common.reflection.AnnotationReader; -import org.hibernate.annotations.common.reflection.ReflectionUtil; -import org.hibernate.boot.jaxb.mapping.spi.AssociationAttribute; -import org.hibernate.boot.jaxb.mapping.spi.AttributesContainer; -import org.hibernate.boot.jaxb.mapping.spi.EntityOrMappedSuperclass; -import org.hibernate.boot.jaxb.mapping.spi.JaxbAssociationOverride; -import org.hibernate.boot.jaxb.mapping.spi.JaxbAttributeOverride; -import org.hibernate.boot.jaxb.mapping.spi.JaxbAttributes; -import org.hibernate.boot.jaxb.mapping.spi.JaxbBasic; -import org.hibernate.boot.jaxb.mapping.spi.JaxbCascadeType; -import org.hibernate.boot.jaxb.mapping.spi.JaxbCollectionTable; -import org.hibernate.boot.jaxb.mapping.spi.JaxbColumn; -import org.hibernate.boot.jaxb.mapping.spi.JaxbColumnResult; -import org.hibernate.boot.jaxb.mapping.spi.JaxbConstructorResult; -import org.hibernate.boot.jaxb.mapping.spi.JaxbConvert; -import org.hibernate.boot.jaxb.mapping.spi.JaxbDiscriminatorColumn; -import org.hibernate.boot.jaxb.mapping.spi.JaxbElementCollection; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEmbeddable; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEmbedded; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEmbeddedId; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEmptyType; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEntity; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityListener; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityListeners; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityResult; -import org.hibernate.boot.jaxb.mapping.spi.JaxbFieldResult; -import org.hibernate.boot.jaxb.mapping.spi.JaxbGeneratedValue; -import org.hibernate.boot.jaxb.mapping.spi.JaxbId; -import org.hibernate.boot.jaxb.mapping.spi.JaxbIdClass; -import org.hibernate.boot.jaxb.mapping.spi.JaxbIndex; -import org.hibernate.boot.jaxb.mapping.spi.JaxbInheritance; -import org.hibernate.boot.jaxb.mapping.spi.JaxbJoinColumn; -import org.hibernate.boot.jaxb.mapping.spi.JaxbJoinTable; -import org.hibernate.boot.jaxb.mapping.spi.JaxbLob; -import org.hibernate.boot.jaxb.mapping.spi.JaxbManyToMany; -import org.hibernate.boot.jaxb.mapping.spi.JaxbManyToOne; -import org.hibernate.boot.jaxb.mapping.spi.JaxbMapKey; -import org.hibernate.boot.jaxb.mapping.spi.JaxbMapKeyClass; -import org.hibernate.boot.jaxb.mapping.spi.JaxbMapKeyColumn; -import org.hibernate.boot.jaxb.mapping.spi.JaxbMapKeyJoinColumn; -import org.hibernate.boot.jaxb.mapping.spi.JaxbMappedSuperclass; -import org.hibernate.boot.jaxb.mapping.spi.JaxbNamedAttributeNode; -import org.hibernate.boot.jaxb.mapping.spi.JaxbNamedEntityGraph; -import org.hibernate.boot.jaxb.mapping.spi.JaxbNamedNativeQuery; -import org.hibernate.boot.jaxb.mapping.spi.JaxbNamedQuery; -import org.hibernate.boot.jaxb.mapping.spi.JaxbNamedStoredProcedureQuery; -import org.hibernate.boot.jaxb.mapping.spi.JaxbNamedSubgraph; -import org.hibernate.boot.jaxb.mapping.spi.JaxbOneToMany; -import org.hibernate.boot.jaxb.mapping.spi.JaxbOneToOne; -import org.hibernate.boot.jaxb.mapping.spi.JaxbOrderColumn; -import org.hibernate.boot.jaxb.mapping.spi.JaxbPrimaryKeyJoinColumn; -import org.hibernate.boot.jaxb.mapping.spi.JaxbQueryHint; -import org.hibernate.boot.jaxb.mapping.spi.JaxbSecondaryTable; -import org.hibernate.boot.jaxb.mapping.spi.JaxbSequenceGenerator; -import org.hibernate.boot.jaxb.mapping.spi.JaxbSqlResultSetMapping; -import org.hibernate.boot.jaxb.mapping.spi.JaxbStoredProcedureParameter; -import org.hibernate.boot.jaxb.mapping.spi.JaxbTable; -import org.hibernate.boot.jaxb.mapping.spi.JaxbTableGenerator; -import org.hibernate.boot.jaxb.mapping.spi.JaxbTransient; -import org.hibernate.boot.jaxb.mapping.spi.JaxbUniqueConstraint; -import org.hibernate.boot.jaxb.mapping.spi.JaxbVersion; -import org.hibernate.boot.jaxb.mapping.spi.LifecycleCallbackContainer; -import org.hibernate.boot.jaxb.mapping.spi.ManagedType; -import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; -import org.hibernate.boot.spi.BootstrapContext; -import org.hibernate.boot.spi.ClassLoaderAccess; -import org.hibernate.cfg.annotations.reflection.PersistentAttributeFilter; -import org.hibernate.internal.CoreLogging; -import org.hibernate.internal.CoreMessageLogger; -import org.hibernate.internal.util.StringHelper; - import static org.hibernate.cfg.annotations.reflection.internal.PropertyMappingElementCollector.JAXB_TRANSIENT_NAME; import static org.hibernate.cfg.annotations.reflection.internal.PropertyMappingElementCollector.PERSISTENT_ATTRIBUTE_NAME; @@ -300,6 +304,7 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { annotationToXml.put( Convert.class, "convert" ); annotationToXml.put( Converts.class, "convert" ); annotationToXml.put( ConstructorResult.class, "constructor-result" ); + } private final XMLContext xmlContext; @@ -412,7 +417,7 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { XMLContext.Default defaults = xmlContext.getDefaultWithoutGlobalCatalogAndSchema( className ); if ( className != null && propertyName == null ) { //is a class - ManagedType managedTypeOverride = xmlContext.getManagedTypeOverride( className ); + final ManagedType managedTypeOverride = xmlContext.getManagedTypeOverride( className ); Annotation[] annotations = getPhysicalAnnotations(); List annotationList = new ArrayList<>( annotations.length + 5 ); annotationsMap = new HashMap<>( annotations.length + 5 ); @@ -430,6 +435,7 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { addIfNotNull( annotationList, getPrimaryKeyJoinColumns( managedTypeOverride, defaults ) ); addIfNotNull( annotationList, getIdClass( managedTypeOverride, defaults ) ); addIfNotNull( annotationList, getCacheable( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getCaching( managedTypeOverride, defaults ) ); addIfNotNull( annotationList, getInheritance( managedTypeOverride, defaults ) ); addIfNotNull( annotationList, getDiscriminatorValue( managedTypeOverride, defaults ) ); addIfNotNull( annotationList, getDiscriminatorColumn( managedTypeOverride, defaults ) ); @@ -455,8 +461,8 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { checkForOrphanProperties( managedTypeOverride ); } else if ( className != null ) { //&& propertyName != null ) { //always true but less confusing - ManagedType managedTypeOverride = xmlContext.getManagedTypeOverride( className ); - JaxbEntityListener entityListenerOverride = xmlContext.getEntityListenerOverride( className ); + final ManagedType managedTypeOverride = xmlContext.getManagedTypeOverride( className ); + final JaxbEntityListener entityListenerOverride = xmlContext.getEntityListenerOverride( className ); Annotation[] annotations = getPhysicalAnnotations(); List annotationList = new ArrayList<>( annotations.length + 5 ); annotationsMap = new HashMap<>( annotations.length + 5 ); @@ -509,13 +515,17 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { } } + private void remove(List annotationList, Class annotationToRemove) { + annotationList.removeIf( next -> next.getClass().equals( annotationToRemove ) ); + } + private Annotation getConvertsForAttribute(PropertyMappingElementCollector elementsForProperty, XMLContext.Default defaults) { // NOTE : we use a map here to make sure that an xml and annotation referring to the same attribute // properly overrides. Very sparse map, yes, but easy setup. // todo : revisit this // although bear in mind that this code is no longer used in 5.0... - final Map convertAnnotationsMap = new HashMap<>(); + final Map convertAnnotationsMap = new HashMap<>(); for ( JaxbBasic element : elementsForProperty.getBasic() ) { JaxbConvert convert = element.getConvert(); @@ -551,7 +561,7 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { private Converts getConverts(ManagedType root, XMLContext.Default defaults) { // NOTE : we use a map here to make sure that an xml and annotation referring to the same attribute // properly overrides. Bit sparse, but easy... - final Map convertAnnotationsMap = new HashMap<>(); + final Map convertAnnotationsMap = new HashMap<>(); if ( root instanceof JaxbEntity ) { applyXmlDefinedConverts( ( (JaxbEntity) root ).getConvert(), defaults, null, convertAnnotationsMap ); @@ -577,7 +587,7 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { List elements, XMLContext.Default defaults, String attributeNamePrefix, - Map convertAnnotationsMap) { + Map convertAnnotationsMap) { for ( JaxbConvert convertElement : elements ) { final AnnotationDescriptor convertAnnotationDescriptor = new AnnotationDescriptor( Convert.class ); copyAttribute( convertAnnotationDescriptor, "attribute-name", convertElement.getAttributeName(), false ); @@ -678,14 +688,14 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { checkForOrphanProperties( jaxbAttributes.getEmbeddedId(), properties, PERSISTENT_ATTRIBUTE_NAME ); checkForOrphanProperties( jaxbAttributes.getVersion(), properties, PERSISTENT_ATTRIBUTE_NAME ); } - checkForOrphanProperties( container.getBasic(), properties, PERSISTENT_ATTRIBUTE_NAME ); - checkForOrphanProperties( container.getManyToOne(), properties, PERSISTENT_ATTRIBUTE_NAME ); - checkForOrphanProperties( container.getOneToMany(), properties, PERSISTENT_ATTRIBUTE_NAME ); - checkForOrphanProperties( container.getOneToOne(), properties, PERSISTENT_ATTRIBUTE_NAME ); - checkForOrphanProperties( container.getManyToMany(), properties, PERSISTENT_ATTRIBUTE_NAME ); - checkForOrphanProperties( container.getElementCollection(), properties, PERSISTENT_ATTRIBUTE_NAME ); - checkForOrphanProperties( container.getEmbedded(), properties, PERSISTENT_ATTRIBUTE_NAME ); - checkForOrphanProperties( container.getTransient(), properties, JAXB_TRANSIENT_NAME ); + checkForOrphanProperties( container.getBasicAttributes(), properties, PERSISTENT_ATTRIBUTE_NAME ); + checkForOrphanProperties( container.getManyToOneAttributes(), properties, PERSISTENT_ATTRIBUTE_NAME ); + checkForOrphanProperties( container.getOneToManyAttributes(), properties, PERSISTENT_ATTRIBUTE_NAME ); + checkForOrphanProperties( container.getOneToOneAttributes(), properties, PERSISTENT_ATTRIBUTE_NAME ); + checkForOrphanProperties( container.getManyToManyAttributes(), properties, PERSISTENT_ATTRIBUTE_NAME ); + checkForOrphanProperties( container.getElementCollectionAttributes(), properties, PERSISTENT_ATTRIBUTE_NAME ); + checkForOrphanProperties( container.getEmbeddedAttributes(), properties, PERSISTENT_ATTRIBUTE_NAME ); + checkForOrphanProperties( container.getTransients(), properties, JAXB_TRANSIENT_NAME ); } } @@ -811,7 +821,7 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { private EntityListeners getEntityListeners(ManagedType root, XMLContext.Default defaults) { JaxbEntityListeners element = root instanceof EntityOrMappedSuperclass ? ( (EntityOrMappedSuperclass) root ).getEntityListeners() : null; if ( element != null ) { - List entityListenerClasses = new ArrayList<>(); + final List> entityListenerClasses = new ArrayList<>(); for ( JaxbEntityListener subelement : element.getEntityListener() ) { String className = subelement.getClazz(); try { @@ -821,14 +831,14 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { ) ); } - catch ( ClassLoadingException e ) { + catch (ClassLoadingException e) { throw new AnnotationException( "Unable to find class: " + className, e ); } } AnnotationDescriptor ad = new AnnotationDescriptor( EntityListeners.class ); - ad.setValue( "value", entityListenerClasses.toArray( new Class[entityListenerClasses.size()] ) ); + ad.setValue( "value", entityListenerClasses.toArray( new Class[0] ) ); return AnnotationFactory.create( ad ); } else if ( defaults.canUseJavaAnnotations() ) { @@ -1215,7 +1225,7 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { joinColumns.add( AnnotationFactory.create( column ) ); } } - return joinColumns.toArray( new MapKeyJoinColumn[joinColumns.size()] ); + return joinColumns.toArray( new MapKeyJoinColumn[0] ); } private AttributeOverrides getMapKeyAttributeOverrides(List elements, XMLContext.Default defaults) { @@ -1223,7 +1233,27 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { return mergeAttributeOverrides( defaults, attributes, false ); } - private Cacheable getCacheable(ManagedType root, XMLContext.Default defaults){ + private Cache getCaching(ManagedType root, XMLContext.Default defaults) { + if ( root instanceof JaxbEntity ) { + final JaxbCaching caching = ( (JaxbEntity) root ).getCaching(); + if ( caching != null ) { + final AnnotationDescriptor ad = new AnnotationDescriptor( Cache.class ); + ad.setValue( "usage", CacheConcurrencyStrategy.fromAccessType( caching.getAccess() ) ); + ad.setValue( "region", caching.getRegion() ); + ad.setValue( "include", caching.getInclude().value() ); + return AnnotationFactory.create( ad ); + } + } + + if ( defaults.canUseJavaAnnotations() ) { + return getPhysicalAnnotation( Cache.class ); + } + else { + return null; + } + } + + private Cacheable getCacheable(ManagedType root, XMLContext.Default defaults) { if ( root instanceof JaxbEntity ) { Boolean attValue = ( (JaxbEntity) root ).isCacheable(); if ( attValue != null ) { @@ -1730,14 +1760,9 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { } List columns = new ArrayList<>( 1 ); columns.add( getColumn( element, false, nodeName ) ); - if ( columns.size() > 0 ) { - AnnotationDescriptor columnsDescr = new AnnotationDescriptor( Columns.class ); - columnsDescr.setValue( "columns", columns.toArray( new Column[columns.size()] ) ); - return AnnotationFactory.create( columnsDescr ); - } - else { - return null; - } + AnnotationDescriptor columnsDescr = new AnnotationDescriptor( Columns.class ); + columnsDescr.setValue( "columns", columns.toArray( new Column[ columns.size() ] ) ); + return AnnotationFactory.create( columnsDescr ); } private Columns buildColumns(List elements, String nodeName) { @@ -1747,7 +1772,7 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { } if ( columns.size() > 0 ) { AnnotationDescriptor columnsDescr = new AnnotationDescriptor( Columns.class ); - columnsDescr.setValue( "columns", columns.toArray( new Column[columns.size()] ) ); + columnsDescr.setValue( "columns", columns.toArray( new Column[ columns.size() ] ) ); return AnnotationFactory.create( columnsDescr ); } else { @@ -1804,11 +1829,11 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { /** * @param mergeWithAnnotations Whether to use Java annotations for this - * element, if present and not disabled by the XMLContext defaults. - * In some contexts (such as an element-collection mapping) merging + * element, if present and not disabled by the XMLContext defaults. + * In some contexts (such as an element-collection mapping) merging */ private AssociationOverrides getAssociationOverrides(List elements, XMLContext.Default defaults, - boolean mergeWithAnnotations) { + boolean mergeWithAnnotations) { List attributes = buildAssociationOverrides( elements, defaults ); if ( mergeWithAnnotations && defaults.canUseJavaAnnotations() ) { AssociationOverride annotation = getPhysicalAnnotation( AssociationOverride.class ); @@ -1891,12 +1916,12 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { /** * @param mergeWithAnnotations Whether to use Java annotations for this - * element, if present and not disabled by the XMLContext defaults. - * In some contexts (such as an association mapping) merging with - * annotations is never allowed. + * element, if present and not disabled by the XMLContext defaults. + * In some contexts (such as an association mapping) merging with + * annotations is never allowed. */ private AttributeOverrides getAttributeOverrides(List elements, XMLContext.Default defaults, - boolean mergeWithAnnotations) { + boolean mergeWithAnnotations) { List attributes = buildAttributeOverrides( elements, "attribute-override" ); return mergeAttributeOverrides( defaults, attributes, mergeWithAnnotations ); } @@ -2002,23 +2027,27 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { } private ExcludeSuperclassListeners getExcludeSuperclassListeners(ManagedType root, XMLContext.Default defaults) { - return (ExcludeSuperclassListeners) getMarkerAnnotation( ExcludeSuperclassListeners.class, + return (ExcludeSuperclassListeners) getMarkerAnnotation( + ExcludeSuperclassListeners.class, root instanceof EntityOrMappedSuperclass ? ( (EntityOrMappedSuperclass) root ).getExcludeSuperclassListeners() : null, - defaults ); + defaults + ); } private ExcludeDefaultListeners getExcludeDefaultListeners(ManagedType root, XMLContext.Default defaults) { - return (ExcludeDefaultListeners) getMarkerAnnotation( ExcludeDefaultListeners.class, + return (ExcludeDefaultListeners) getMarkerAnnotation( + ExcludeDefaultListeners.class, root instanceof EntityOrMappedSuperclass ? ( (EntityOrMappedSuperclass) root ).getExcludeDefaultListeners() : null, - defaults ); + defaults + ); } private Annotation getMarkerAnnotation(Class clazz, JaxbEmptyType element, - XMLContext.Default defaults) { + XMLContext.Default defaults) { if ( element != null ) { return AnnotationFactory.create( new AnnotationDescriptor( clazz ) ); } @@ -2033,7 +2062,7 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { private SqlResultSetMappings getSqlResultSetMappings(ManagedType root, XMLContext.Default defaults) { List results = root instanceof JaxbEntity - ? buildSqlResultsetMappings( ( (JaxbEntity) root ).getSqlResultSetMapping(), defaults, classLoaderAccess ) + ? buildSqlResultSetMappings( ( (JaxbEntity) root ).getSqlResultSetMapping(), defaults, classLoaderAccess ) : new ArrayList<>(); if ( defaults.canUseJavaAnnotations() ) { SqlResultSetMapping annotation = getPhysicalAnnotation( SqlResultSetMapping.class ); @@ -2080,8 +2109,8 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { String annotationAttributeName, List subgraphNodes, ClassLoaderAccess classLoaderAccess) { - List annSubgraphNodes = new ArrayList<>( ); - for(JaxbNamedSubgraph subgraphNode : subgraphNodes){ + List annSubgraphNodes = new ArrayList<>(); + for ( JaxbNamedSubgraph subgraphNode : subgraphNodes ) { AnnotationDescriptor annSubgraphNode = new AnnotationDescriptor( NamedSubgraph.class ); copyAttribute( annSubgraphNode, "name", subgraphNode.getName(), true ); String clazzName = subgraphNode.getClazz(); @@ -2099,19 +2128,19 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { annSubgraphNodes.add( AnnotationFactory.create( annSubgraphNode ) ); } - ann.setValue( annotationAttributeName, annSubgraphNodes.toArray( new NamedSubgraph[annSubgraphNodes.size()] ) ); + ann.setValue( annotationAttributeName, annSubgraphNodes.toArray( new NamedSubgraph[ annSubgraphNodes.size() ] ) ); } private static void bindNamedAttributeNodes(List elements, AnnotationDescriptor ann) { - List annNamedAttributeNodes = new ArrayList<>( ); - for( JaxbNamedAttributeNode element : elements){ + List annNamedAttributeNodes = new ArrayList<>(); + for ( JaxbNamedAttributeNode element : elements ) { AnnotationDescriptor annNamedAttributeNode = new AnnotationDescriptor( NamedAttributeNode.class ); - copyAttribute( annNamedAttributeNode, "value", "name", element.getName(),true ); + copyAttribute( annNamedAttributeNode, "value", "name", element.getName(), true ); copyAttribute( annNamedAttributeNode, "subgraph", element.getSubgraph(), false ); copyAttribute( annNamedAttributeNode, "key-subgraph", element.getKeySubgraph(), false ); annNamedAttributeNodes.add( AnnotationFactory.create( annNamedAttributeNode ) ); } - ann.setValue( "attributeNodes", annNamedAttributeNodes.toArray( new NamedAttributeNode[annNamedAttributeNodes.size()] ) ); + ann.setValue( "attributeNodes", annNamedAttributeNodes.toArray( new NamedAttributeNode[0] ) ); } public static List buildNamedStoreProcedureQueries( @@ -2152,7 +2181,7 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { ann.setValue( "parameters", - storedProcedureParameters.toArray( new StoredProcedureParameter[storedProcedureParameters.size()] ) + storedProcedureParameters.toArray( new StoredProcedureParameter[0] ) ); List> returnClasses = new ArrayList<>(); @@ -2168,7 +2197,7 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { } returnClasses.add( clazz ); } - ann.setValue( "resultClasses", returnClasses.toArray( new Class[returnClasses.size()] ) ); + ann.setValue( "resultClasses", returnClasses.toArray( new Class[0] ) ); ann.setValue( "resultSetMappings", element.getResultSetMapping().toArray( new String[0] ) ); @@ -2179,7 +2208,7 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { } - public static List buildSqlResultsetMappings( + public static List buildSqlResultSetMappings( List elements, XMLContext.Default defaults, ClassLoaderAccess classLoaderAccess) { @@ -2501,7 +2530,7 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { } } - private static void buildQueryHints(List elements, AnnotationDescriptor ann){ + private static void buildQueryHints(List elements, AnnotationDescriptor ann) { List queryHints = new ArrayList<>( elements.size() ); for ( JaxbQueryHint hint : elements ) { AnnotationDescriptor hintDescriptor = new AnnotationDescriptor( QueryHint.class ); @@ -2566,7 +2595,10 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { } private TableGenerator getTableGenerator(ManagedType root, XMLContext.Default defaults) { - return getTableGenerator( root instanceof JaxbEntity ? ( (JaxbEntity) root ).getTableGenerator() : null, defaults ); + return getTableGenerator( + root instanceof JaxbEntity ? ( (JaxbEntity) root ).getTableGenerator() : null, + defaults + ); } private TableGenerator getTableGenerator(JaxbTableGenerator element, XMLContext.Default defaults) { @@ -2631,8 +2663,10 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { } private SequenceGenerator getSequenceGenerator(ManagedType root, XMLContext.Default defaults) { - return getSequenceGenerator( root instanceof JaxbEntity ? ( (JaxbEntity) root ).getSequenceGenerator() : null, - defaults ); + return getSequenceGenerator( + root instanceof JaxbEntity ? ( (JaxbEntity) root ).getSequenceGenerator() : null, + defaults + ); } private SequenceGenerator getSequenceGenerator(JaxbSequenceGenerator element, XMLContext.Default defaults) { @@ -2716,8 +2750,9 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { } private IdClass getIdClass(ManagedType root, XMLContext.Default defaults) { - JaxbIdClass element = root instanceof EntityOrMappedSuperclass ? - ( (EntityOrMappedSuperclass) root ).getIdClass() : null; + final JaxbIdClass element = root instanceof EntityOrMappedSuperclass + ? ( (EntityOrMappedSuperclass) root ).getIdClass() + : null; if ( element != null ) { String className = element.getClazz(); if ( className != null ) { @@ -2756,8 +2791,10 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { * element, if present and not disabled by the XMLContext defaults. * In some contexts (such as an association mapping) merging with */ - private PrimaryKeyJoinColumns getPrimaryKeyJoinColumns(List elements, - XMLContext.Default defaults, boolean mergeWithAnnotations) { + private PrimaryKeyJoinColumns getPrimaryKeyJoinColumns( + List elements, + XMLContext.Default defaults, + boolean mergeWithAnnotations) { PrimaryKeyJoinColumn[] columns = buildPrimaryKeyJoinColumns( elements ); if ( mergeWithAnnotations ) { if ( columns.length == 0 && defaults.canUseJavaAnnotations() ) { @@ -2835,8 +2872,19 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { } } + private Subselect getTableExpression(JaxbEntity entity, XMLContext.Default defaults) { + final String tableExpression = entity.getTableExpression(); + if ( StringHelper.isEmpty( tableExpression ) ) { + return null; + } + + final AnnotationDescriptor annotation = new AnnotationDescriptor( Subselect.class ); + annotation.setValue( "value", tableExpression ); + return AnnotationFactory.create( annotation ); + } + private Table getTable(ManagedType root, XMLContext.Default defaults) { - JaxbTable element = root instanceof JaxbEntity ? ( (JaxbEntity) root ).getTable() : null; + final JaxbTable element = root instanceof JaxbEntity ? ( (JaxbEntity) root ).getTable() : null; if ( element == null ) { //no element but might have some default or some annotation if ( StringHelper.isNotEmpty( defaults.getCatalog() ) @@ -2890,9 +2938,10 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { } private SecondaryTables getSecondaryTables(ManagedType root, XMLContext.Default defaults) { - List elements = root instanceof JaxbEntity ? - ( (JaxbEntity) root ).getSecondaryTable() : Collections.emptyList(); - List secondaryTables = new ArrayList<>( 3 ); + final List elements = root instanceof JaxbEntity + ? ( (JaxbEntity) root ).getSecondaryTable() + : Collections.emptyList(); + final List secondaryTables = new ArrayList<>( 3 ); for ( JaxbSecondaryTable element : elements ) { AnnotationDescriptor annotation = new AnnotationDescriptor( SecondaryTable.class ); copyAttribute( annotation, "name", element.getName(), false ); @@ -2964,42 +3013,43 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { } } } + private static void buildIndex(AnnotationDescriptor annotation, List elements) { - Index[] indexes = new Index[elements.size()]; + Index[] indexes = new Index[ elements.size() ]; int i = 0; for ( JaxbIndex element : elements ) { AnnotationDescriptor indexAnn = new AnnotationDescriptor( Index.class ); copyAttribute( indexAnn, "name", element.getName(), false ); copyAttribute( indexAnn, "column-list", element.getColumnList(), true ); copyAttribute( indexAnn, "unique", element.isUnique(), false ); - indexes[i++] = AnnotationFactory.create( indexAnn ); + indexes[ i++ ] = AnnotationFactory.create( indexAnn ); } annotation.setValue( "indexes", indexes ); } private static void buildUniqueConstraints(AnnotationDescriptor annotation, - List elements) { - UniqueConstraint[] uniqueConstraints = new UniqueConstraint[elements.size()]; + List elements) { + UniqueConstraint[] uniqueConstraints = new UniqueConstraint[ elements.size() ]; int i = 0; for ( JaxbUniqueConstraint element : elements ) { - String[] columnNames = element.getColumnName().toArray( new String[0] ); + String[] columnNames = element.getColumnName().toArray( new String[ 0 ] ); AnnotationDescriptor ucAnn = new AnnotationDescriptor( UniqueConstraint.class ); copyAttribute( ucAnn, "name", element.getName(), false ); ucAnn.setValue( "columnNames", columnNames ); - uniqueConstraints[i++] = AnnotationFactory.create( ucAnn ); + uniqueConstraints[ i++ ] = AnnotationFactory.create( ucAnn ); } annotation.setValue( "uniqueConstraints", uniqueConstraints ); } private PrimaryKeyJoinColumn[] buildPrimaryKeyJoinColumns(List elements) { - PrimaryKeyJoinColumn[] pkJoinColumns = new PrimaryKeyJoinColumn[elements.size()]; + PrimaryKeyJoinColumn[] pkJoinColumns = new PrimaryKeyJoinColumn[ elements.size() ]; int i = 0; for ( JaxbPrimaryKeyJoinColumn element : elements ) { AnnotationDescriptor pkAnn = new AnnotationDescriptor( PrimaryKeyJoinColumn.class ); copyAttribute( pkAnn, "name", element.getName(), false ); copyAttribute( pkAnn, "referenced-column-name", element.getReferencedColumnName(), false ); copyAttribute( pkAnn, "column-definition", element.getColumnDefinition(), false ); - pkJoinColumns[i++] = AnnotationFactory.create( pkAnn ); + pkJoinColumns[ i++ ] = AnnotationFactory.create( pkAnn ); } return pkJoinColumns; } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java index 0bb0a99093..727c37d5cf 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java @@ -2,7 +2,7 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ package org.hibernate.cfg.annotations.reflection.internal; @@ -12,6 +12,17 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; + +import org.hibernate.annotations.common.reflection.AnnotationReader; +import org.hibernate.annotations.common.reflection.MetadataProvider; +import org.hibernate.annotations.common.reflection.java.JavaMetadataProvider; +import org.hibernate.boot.jaxb.mapping.JaxbEntityMappings; +import org.hibernate.boot.jaxb.mapping.JaxbSequenceGenerator; +import org.hibernate.boot.jaxb.mapping.JaxbTableGenerator; +import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; +import org.hibernate.boot.spi.BootstrapContext; +import org.hibernate.boot.spi.ClassLoaderAccess; + import jakarta.persistence.EntityListeners; import jakarta.persistence.NamedNativeQuery; import jakarta.persistence.NamedQuery; @@ -20,16 +31,6 @@ import jakarta.persistence.SequenceGenerator; import jakarta.persistence.SqlResultSetMapping; import jakarta.persistence.TableGenerator; -import org.hibernate.annotations.common.reflection.AnnotationReader; -import org.hibernate.annotations.common.reflection.MetadataProvider; -import org.hibernate.annotations.common.reflection.java.JavaMetadataProvider; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; -import org.hibernate.boot.jaxb.mapping.spi.JaxbSequenceGenerator; -import org.hibernate.boot.jaxb.mapping.spi.JaxbTableGenerator; -import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; -import org.hibernate.boot.spi.BootstrapContext; -import org.hibernate.boot.spi.ClassLoaderAccess; - /** * MetadataProvider aware of the JPA Deployment descriptor (orm.xml, ...). * @@ -105,14 +106,14 @@ public final class JPAXMLOverriddenMetadataProvider implements MetadataProvider try { entityListeners.add( classLoaderAccess.classForName( className ) ); } - catch ( ClassLoadingException e ) { + catch (ClassLoadingException e) { throw new IllegalStateException( "Default entity listener class not found: " + className ); } } defaults.put( EntityListeners.class, entityListeners ); for ( JaxbEntityMappings entityMappings : xmlContext.getAllDocuments() ) { List jaxbSequenceGenerators = entityMappings.getSequenceGenerator(); - List sequenceGenerators = ( List ) defaults.get( SequenceGenerator.class ); + List sequenceGenerators = (List) defaults.get( SequenceGenerator.class ); if ( sequenceGenerators == null ) { sequenceGenerators = new ArrayList<>(); defaults.put( SequenceGenerator.class, sequenceGenerators ); @@ -122,7 +123,7 @@ public final class JPAXMLOverriddenMetadataProvider implements MetadataProvider } List jaxbTableGenerators = entityMappings.getTableGenerator(); - List tableGenerators = ( List ) defaults.get( TableGenerator.class ); + List tableGenerators = (List) defaults.get( TableGenerator.class ); if ( tableGenerators == null ) { tableGenerators = new ArrayList<>(); defaults.put( TableGenerator.class, tableGenerators ); @@ -130,7 +131,8 @@ public final class JPAXMLOverriddenMetadataProvider implements MetadataProvider for ( JaxbTableGenerator element : jaxbTableGenerators ) { tableGenerators.add( JPAXMLOverriddenAnnotationReader.buildTableGeneratorAnnotation( - element, xmlDefaults + element, + xmlDefaults ) ); } @@ -141,7 +143,7 @@ public final class JPAXMLOverriddenMetadataProvider implements MetadataProvider defaults.put( NamedQuery.class, namedQueries ); } List currentNamedQueries = JPAXMLOverriddenAnnotationReader.buildNamedQueries( - entityMappings.getNamedQuery(), + entityMappings.getNamedQueries(), xmlDefaults, classLoaderAccess ); @@ -153,7 +155,7 @@ public final class JPAXMLOverriddenMetadataProvider implements MetadataProvider defaults.put( NamedNativeQuery.class, namedNativeQueries ); } List currentNamedNativeQueries = JPAXMLOverriddenAnnotationReader.buildNamedNativeQueries( - entityMappings.getNamedNativeQuery(), + entityMappings.getNamedNativeQueries(), xmlDefaults, classLoaderAccess ); @@ -166,8 +168,8 @@ public final class JPAXMLOverriddenMetadataProvider implements MetadataProvider sqlResultSetMappings = new ArrayList<>(); defaults.put( SqlResultSetMapping.class, sqlResultSetMappings ); } - List currentSqlResultSetMappings = JPAXMLOverriddenAnnotationReader.buildSqlResultsetMappings( - entityMappings.getSqlResultSetMapping(), + List currentSqlResultSetMappings = JPAXMLOverriddenAnnotationReader.buildSqlResultSetMappings( + entityMappings.getSqlResultSetMappings(), xmlDefaults, classLoaderAccess ); @@ -180,7 +182,7 @@ public final class JPAXMLOverriddenMetadataProvider implements MetadataProvider } List currentNamedStoredProcedureQueries = JPAXMLOverriddenAnnotationReader .buildNamedStoreProcedureQueries( - entityMappings.getNamedStoredProcedureQuery(), + entityMappings.getNamedProcedureQueries(), xmlDefaults, classLoaderAccess ); diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/PropertyMappingElementCollector.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/PropertyMappingElementCollector.java index 97bf6b89ea..27f7e50944 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/PropertyMappingElementCollector.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/PropertyMappingElementCollector.java @@ -1,8 +1,8 @@ /* * 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 + * 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.cfg.annotations.reflection.internal; @@ -11,29 +11,30 @@ import java.util.Collections; import java.util.List; import java.util.function.Function; -import org.hibernate.boot.jaxb.mapping.spi.AttributesContainer; -import org.hibernate.boot.jaxb.mapping.spi.JaxbAttributes; -import org.hibernate.boot.jaxb.mapping.spi.JaxbBasic; -import org.hibernate.boot.jaxb.mapping.spi.JaxbElementCollection; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEmbedded; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEmbeddedId; -import org.hibernate.boot.jaxb.mapping.spi.JaxbId; -import org.hibernate.boot.jaxb.mapping.spi.JaxbManyToMany; -import org.hibernate.boot.jaxb.mapping.spi.JaxbManyToOne; -import org.hibernate.boot.jaxb.mapping.spi.JaxbOneToMany; -import org.hibernate.boot.jaxb.mapping.spi.JaxbOneToOne; -import org.hibernate.boot.jaxb.mapping.spi.JaxbPostLoad; -import org.hibernate.boot.jaxb.mapping.spi.JaxbPostPersist; -import org.hibernate.boot.jaxb.mapping.spi.JaxbPostRemove; -import org.hibernate.boot.jaxb.mapping.spi.JaxbPostUpdate; -import org.hibernate.boot.jaxb.mapping.spi.JaxbPrePersist; -import org.hibernate.boot.jaxb.mapping.spi.JaxbPreRemove; -import org.hibernate.boot.jaxb.mapping.spi.JaxbPreUpdate; -import org.hibernate.boot.jaxb.mapping.spi.JaxbTransient; -import org.hibernate.boot.jaxb.mapping.spi.JaxbVersion; -import org.hibernate.boot.jaxb.mapping.spi.LifecycleCallback; -import org.hibernate.boot.jaxb.mapping.spi.LifecycleCallbackContainer; -import org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute; +import org.hibernate.boot.jaxb.mapping.AttributesContainer; +import org.hibernate.boot.jaxb.mapping.JaxbAttributes; +import org.hibernate.boot.jaxb.mapping.JaxbBasic; +import org.hibernate.boot.jaxb.mapping.JaxbElementCollection; +import org.hibernate.boot.jaxb.mapping.JaxbEmbedded; +import org.hibernate.boot.jaxb.mapping.JaxbEmbeddedId; +import org.hibernate.boot.jaxb.mapping.JaxbId; +import org.hibernate.boot.jaxb.mapping.JaxbManyToMany; +import org.hibernate.boot.jaxb.mapping.JaxbManyToOne; +import org.hibernate.boot.jaxb.mapping.JaxbOneToMany; +import org.hibernate.boot.jaxb.mapping.JaxbOneToOne; +import org.hibernate.boot.jaxb.mapping.JaxbPostLoad; +import org.hibernate.boot.jaxb.mapping.JaxbPostPersist; +import org.hibernate.boot.jaxb.mapping.JaxbPostRemove; +import org.hibernate.boot.jaxb.mapping.JaxbPostUpdate; +import org.hibernate.boot.jaxb.mapping.JaxbPrePersist; +import org.hibernate.boot.jaxb.mapping.JaxbPreRemove; +import org.hibernate.boot.jaxb.mapping.JaxbPreUpdate; +import org.hibernate.boot.jaxb.mapping.JaxbTransient; +import org.hibernate.boot.jaxb.mapping.JaxbVersion; +import org.hibernate.boot.jaxb.mapping.LifecycleCallback; +import org.hibernate.boot.jaxb.mapping.LifecycleCallbackContainer; +import org.hibernate.boot.jaxb.mapping.PersistentAttribute; + /** * Reproduces what we used to do with a {@code List} in {@link JPAXMLOverriddenAnnotationReader}, @@ -52,14 +53,14 @@ final class PropertyMappingElementCollector { private List id; private List embeddedId; - private List basic; private List version; - private List manyToOne; - private List oneToMany; - private List oneToOne; - private List manyToMany; - private List elementCollection; + private List basic; private List embedded; + private List oneToOne; + private List manyToOne; + private List elementCollection; + private List oneToMany; + private List manyToMany; private List _transient; private List prePersist; @@ -95,19 +96,19 @@ final class PropertyMappingElementCollector { public void collectPersistentAttributesIfMatching(AttributesContainer container) { if ( container instanceof JaxbAttributes ) { - JaxbAttributes jaxbAttributes = (JaxbAttributes) container; + final JaxbAttributes jaxbAttributes = (JaxbAttributes) container; id = collectIfMatching( id, jaxbAttributes.getId(), PERSISTENT_ATTRIBUTE_NAME ); embeddedId = collectIfMatching( embeddedId, jaxbAttributes.getEmbeddedId(), PERSISTENT_ATTRIBUTE_NAME ); version = collectIfMatching( version, jaxbAttributes.getVersion(), PERSISTENT_ATTRIBUTE_NAME ); } - basic = collectIfMatching( basic, container.getBasic(), PERSISTENT_ATTRIBUTE_NAME ); - manyToOne = collectIfMatching( manyToOne, container.getManyToOne(), PERSISTENT_ATTRIBUTE_NAME ); - oneToMany = collectIfMatching( oneToMany, container.getOneToMany(), PERSISTENT_ATTRIBUTE_NAME ); - oneToOne = collectIfMatching( oneToOne, container.getOneToOne(), PERSISTENT_ATTRIBUTE_NAME ); - manyToMany = collectIfMatching( manyToMany, container.getManyToMany(), PERSISTENT_ATTRIBUTE_NAME ); - elementCollection = collectIfMatching( elementCollection, container.getElementCollection(), PERSISTENT_ATTRIBUTE_NAME ); - embedded = collectIfMatching( embedded, container.getEmbedded(), PERSISTENT_ATTRIBUTE_NAME ); - _transient = collectIfMatching( _transient, container.getTransient(), JAXB_TRANSIENT_NAME ); + basic = collectIfMatching( basic, container.getBasicAttributes(), PERSISTENT_ATTRIBUTE_NAME ); + manyToOne = collectIfMatching( manyToOne, container.getManyToOneAttributes(), PERSISTENT_ATTRIBUTE_NAME ); + oneToMany = collectIfMatching( oneToMany, container.getOneToManyAttributes(), PERSISTENT_ATTRIBUTE_NAME ); + oneToOne = collectIfMatching( oneToOne, container.getOneToOneAttributes(), PERSISTENT_ATTRIBUTE_NAME ); + manyToMany = collectIfMatching( manyToMany, container.getManyToManyAttributes(), PERSISTENT_ATTRIBUTE_NAME ); + elementCollection = collectIfMatching( elementCollection, container.getElementCollectionAttributes(), PERSISTENT_ATTRIBUTE_NAME ); + embedded = collectIfMatching( embedded, container.getEmbeddedAttributes(), PERSISTENT_ATTRIBUTE_NAME ); + _transient = collectIfMatching( _transient, container.getTransients(), JAXB_TRANSIENT_NAME ); } public void collectLifecycleCallbacksIfMatching(LifecycleCallbackContainer container) { diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java index 3eaf5149df..a8d4267e23 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java @@ -2,7 +2,7 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ package org.hibernate.cfg.annotations.reflection.internal; @@ -11,20 +11,18 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import jakarta.persistence.AccessType; -import jakarta.persistence.AttributeConverter; import org.hibernate.AnnotationException; import org.hibernate.boot.internal.ClassmateContext; -import org.hibernate.boot.jaxb.mapping.spi.JaxbConverter; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEntity; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityListener; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityListeners; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; -import org.hibernate.boot.jaxb.mapping.spi.JaxbMappedSuperclass; -import org.hibernate.boot.jaxb.mapping.spi.JaxbPersistenceUnitDefaults; -import org.hibernate.boot.jaxb.mapping.spi.JaxbPersistenceUnitMetadata; -import org.hibernate.boot.jaxb.mapping.spi.ManagedType; +import org.hibernate.boot.jaxb.mapping.JaxbConverter; +import org.hibernate.boot.jaxb.mapping.JaxbEntity; +import org.hibernate.boot.jaxb.mapping.JaxbEntityListener; +import org.hibernate.boot.jaxb.mapping.JaxbEntityListeners; +import org.hibernate.boot.jaxb.mapping.JaxbEntityMappings; +import org.hibernate.boot.jaxb.mapping.JaxbMappedSuperclass; +import org.hibernate.boot.jaxb.mapping.JaxbPersistenceUnitDefaults; +import org.hibernate.boot.jaxb.mapping.JaxbPersistenceUnitMetadata; +import org.hibernate.boot.jaxb.mapping.ManagedType; import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor; import org.hibernate.boot.model.convert.spi.ConverterDescriptor; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; @@ -35,6 +33,9 @@ import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.StringHelper; +import jakarta.persistence.AccessType; +import jakarta.persistence.AttributeConverter; + /** * A helper for consuming orm.xml mappings. * @@ -64,21 +65,24 @@ public class XMLContext implements Serializable { * @param entityMappings The xml document to add * @return Add an xml document to this context and return the list of added class names. */ - @SuppressWarnings( "unchecked" ) + @SuppressWarnings("unchecked") public List addDocument(JaxbEntityMappings entityMappings) { hasContext = true; - List addedClasses = new ArrayList<>(); + + final List addedClasses = new ArrayList<>(); + //global defaults - JaxbPersistenceUnitMetadata metadata = entityMappings.getPersistenceUnitMetadata(); + final JaxbPersistenceUnitMetadata metadata = entityMappings.getPersistenceUnitMetadata(); if ( metadata != null ) { if ( globalDefaults == null ) { globalDefaults = new Default(); globalDefaults.setMetadataComplete( - metadata.getXmlMappingMetadataComplete() != null ? - Boolean.TRUE : - null + metadata.getXmlMappingMetadataComplete() != null + ? Boolean.TRUE + : null ); - JaxbPersistenceUnitDefaults defaultElement = metadata.getPersistenceUnitDefaults(); + + final JaxbPersistenceUnitDefaults defaultElement = metadata.getPersistenceUnitDefaults(); if ( defaultElement != null ) { globalDefaults.setSchema( defaultElement.getSchema() ); globalDefaults.setCatalog( defaultElement.getCatalog() ); @@ -102,13 +106,13 @@ public class XMLContext implements Serializable { entityMappingDefault.setAccess( entityMappings.getAccess() ); defaultElements.add( entityMappings ); - setLocalAttributeConverterDefinitions( entityMappings.getConverter(), packageName ); + setLocalAttributeConverterDefinitions( entityMappings.getConverters(), packageName ); - addClass( entityMappings.getEntity(), packageName, entityMappingDefault, addedClasses ); + addClass( entityMappings.getEntities(), packageName, entityMappingDefault, addedClasses ); - addClass( entityMappings.getMappedSuperclass(), packageName, entityMappingDefault, addedClasses ); + addClass( entityMappings.getMappedSuperclasses(), packageName, entityMappingDefault, addedClasses ); - addClass( entityMappings.getEmbeddable(), packageName, entityMappingDefault, addedClasses ); + addClass( entityMappings.getEmbeddables(), packageName, entityMappingDefault, addedClasses ); return addedClasses; } @@ -147,7 +151,7 @@ public class XMLContext implements Serializable { List localAddedClasses = new ArrayList<>(); if ( listeners != null ) { List elements = listeners.getEntityListener(); - for (JaxbEntityListener listener : elements) { + for ( JaxbEntityListener listener : elements ) { String listenerClassName = buildSafeClassName( listener.getClazz(), packageName ); if ( entityListenerOverride.containsKey( listenerClassName ) ) { LOG.duplicateListener( listenerClassName ); @@ -162,7 +166,6 @@ public class XMLContext implements Serializable { return localAddedClasses; } - @SuppressWarnings("unchecked") private void setLocalAttributeConverterDefinitions(List converterElements, String packageName) { for ( JaxbConverter converterElement : converterElements ) { final String className = converterElement.getClazz(); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/config/spi/StandardConverters.java b/hibernate-core/src/main/java/org/hibernate/engine/config/spi/StandardConverters.java index 3f42a6dc5d..27535504eb 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/config/spi/StandardConverters.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/config/spi/StandardConverters.java @@ -15,31 +15,25 @@ import static org.hibernate.engine.config.spi.ConfigurationService.Converter; * @author Steve Ebersole */ public class StandardConverters { - public static final Converter BOOLEAN = new Converter() { - @Override - public Boolean convert(Object value) { - if ( value == null ) { - throw new IllegalArgumentException( "Null value passed to convert" ); - } - - return Boolean.class.isInstance( value ) - ? Boolean.class.cast( value ) - : Boolean.parseBoolean( value.toString() ); + public static final Converter BOOLEAN = (value) -> { + if ( value == null ) { + throw new IllegalArgumentException( "Null value passed to convert" ); } + + return value instanceof Boolean + ? (Boolean) value + : Boolean.parseBoolean( value.toString() ); }; - public static final Converter STRING = new Converter() { - @Override - public String convert(Object value) { - if ( value == null ) { - throw new IllegalArgumentException( "Null value passed to convert" ); - } - - return value.toString(); + public static final Converter STRING = (value) -> { + if ( value == null ) { + throw new IllegalArgumentException( "Null value passed to convert" ); } + + return value.toString(); }; - public static final Converter INTEGER = value -> { + public static final Converter INTEGER = (value) -> { if ( value == null ) { throw new IllegalArgumentException( "Null value passed to convert" ); } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java index a5570df4c0..fa9e183357 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java @@ -2,10 +2,13 @@ * Hibernate, Relational Persistence for Idiomatic Java * * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ package org.hibernate.internal.log; +import org.hibernate.boot.jaxb.SourceType; +import org.hibernate.cfg.AvailableSettings; + import org.jboss.logging.BasicLogger; import org.jboss.logging.Logger; import org.jboss.logging.annotations.LogMessage; @@ -238,4 +241,18 @@ public interface DeprecationLogger extends BasicLogger { value = "Encountered deprecated setting [%s]; instead %s" ) void deprecatedSetting2(String settingName, String alternative); + + /** + * Different from {@link #deprecatedSetting} in that sometimes there is no + * direct alternative + */ + @LogMessage(level = WARN) + @Message( + id = 90000028, + value = "Support for `` is deprecated [%s : %s]; " + + "migrate to orm.xml or mapping.xml, or enable `" + AvailableSettings.TRANSFORM_HBM_XML + + "` for on the fly transformation" + ) + void logDeprecatedHbmXmlProcessing(SourceType sourceType, String name); + } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java index dce6fd91c0..da77896357 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java @@ -264,7 +264,7 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil this.standardServiceRegistry = ssrBuilder.build(); - final MetadataSources metadataSources = new MetadataSources( bsr ); + final MetadataSources metadataSources = new MetadataSources( standardServiceRegistry ); this.metamodelBuilder = (MetadataBuilderImplementor) metadataSources.getMetadataBuilder( standardServiceRegistry ); List attributeConverterDefinitions = applyMappingResources( metadataSources ); diff --git a/hibernate-core/src/main/java/org/hibernate/service/internal/AbstractServiceRegistryImpl.java b/hibernate-core/src/main/java/org/hibernate/service/internal/AbstractServiceRegistryImpl.java index 84ad7ce7e2..ad700222fb 100644 --- a/hibernate-core/src/main/java/org/hibernate/service/internal/AbstractServiceRegistryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/service/internal/AbstractServiceRegistryImpl.java @@ -435,12 +435,39 @@ public abstract class AbstractServiceRegistryImpl } } + @Override + public T fromRegistryOrChildren(Class serviceRole) { + return fromRegistryOrChildren( serviceRole, this, childRegistries ); + } + + public static T fromRegistryOrChildren( + Class serviceRole, + ServiceRegistryImplementor serviceRegistry, + Set childRegistries) { + // prefer `serviceRegistry` + final T localService = serviceRegistry.getService( serviceRole ); + if ( localService != null ) { + return localService; + } + + if ( childRegistries != null ) { + for ( ServiceRegistryImplementor childRegistry : childRegistries ) { + final T extracted = childRegistry.getService( serviceRole ); + if ( extracted != null ) { + return extracted; + } + } + } + + return null; + } + /** * Not intended for general use. We need the ability to stop and "reactivate" a registry to allow * experimentation with technologies such as GraalVM, Quarkus and Cri-O. */ public synchronized void reactivate() { - if ( !active.compareAndSet(false, true) ) { + if ( !active.compareAndSet( false, true ) ) { throw new IllegalStateException( "Was not inactive, could not reactivate!" ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/service/spi/ServiceRegistryImplementor.java b/hibernate-core/src/main/java/org/hibernate/service/spi/ServiceRegistryImplementor.java index 5122727498..023bef2f04 100644 --- a/hibernate-core/src/main/java/org/hibernate/service/spi/ServiceRegistryImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/service/spi/ServiceRegistryImplementor.java @@ -46,4 +46,6 @@ public interface ServiceRegistryImplementor extends ServiceRegistry { * via this callback. */ void deRegisterChild(ServiceRegistryImplementor child); + + T fromRegistryOrChildren(Class serviceRole); } diff --git a/hibernate-core/src/main/resources/org/hibernate/xsd/mapping/mapping-2.1.0.xsd b/hibernate-core/src/main/resources/org/hibernate/xsd/mapping/mapping-3.1.0.xsd similarity index 71% rename from hibernate-core/src/main/resources/org/hibernate/xsd/mapping/mapping-2.1.0.xsd rename to hibernate-core/src/main/resources/org/hibernate/xsd/mapping/mapping-3.1.0.xsd index d1b364771b..63e864a3cd 100644 --- a/hibernate-core/src/main/resources/org/hibernate/xsd/mapping/mapping-2.1.0.xsd +++ b/hibernate-core/src/main/resources/org/hibernate/xsd/mapping/mapping-3.1.0.xsd @@ -1,26 +1,26 @@ + + xmlns="http://www.hibernate.org/xsd/orm/mapping" + xmlns:orm="http://www.hibernate.org/xsd/orm/mapping" + targetNamespace="http://www.hibernate.org/xsd/orm/mapping" + elementFormDefault="qualified" + version="3.1"> + version="3.1"> ... ]]> @@ -33,11 +33,12 @@ + The entity-mappings element is the root element of a mapping file. It contains the following four types of elements: 1. The persistence-unit-metadata element contains metadata - for the entire persistence unit. The behavior is undefined if this element + for the entire persistence unit. It is undefined if this element occurs in multiple mapping files within the same persistence unit. 2. The package, schema, catalog and access elements apply to all of @@ -47,29 +48,23 @@ 3. The sequence-generator, table-generator, converter, named-query, named-native-query, named-stored-procedure-query, and sql-result-set-mapping elements are global to the persistence - unit. - - a. The behavior is undefined when having more than one sequence-generator - or table-generator occur in a persistence unit (whether in the same or - different mapping file). - - b. The behavior is undefined when having more than one named-query, - named-native-query, sql-result-set-mapping, or named-stored-procedure-query - of the same name in a persistence unit (whether in the same or different - mapping file). - - c. The behavior is undefined when having more than one converter for the same - target type in a persistence unit (whether in the same or different mapping file). + unit. It is undefined to have more than one sequence-generator + or table-generator of the same name in the same or different + mapping files in a persistence unit. It is undefined to have + more than one named-query, named-native-query, sql-result-set-mapping, + or named-stored-procedure-query of the same name in the same + or different mapping files in a persistence unit. It is also + undefined to have more than one converter for the same target + type in the same or different mapping files in a persistence unit. 4. The entity, mapped-superclass and embeddable elements each define the mapping information for a managed persistent class. The mapping information contained in these elements may be complete or it may be partial. + - - @@ -81,22 +76,29 @@ - + + + + - - - + + + + + + - + + @@ -108,36 +110,49 @@ - - - - - - - - + + + + - + + - - - - - - + + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + @@ -145,12 +160,14 @@ - Metadata that applies to the persistence unit and not just to the mapping - file in which it is contained. + + Metadata that applies to the persistence unit and not just to + the mapping file in which it is contained. If the xml-mapping-metadata-complete element is specified, the complete set of mapping metadata for the persistence unit is contained in the XML mapping files for the persistence unit. + @@ -160,31 +177,29 @@ + - These defaults are applied to the persistence unit as a whole unless they - are overridden by local annotation or XML element settings. + + These defaults are applied to the persistence unit as a whole + unless they are overridden by local annotation or XML + element settings. schema - Used as the schema for all tables, secondary tables, join tables, collection tables, sequence generators, and table generators that apply to the persistence unit - catalog - Used as the catalog for all tables, secondary tables, join tables, collection tables, sequence generators, and table generators that apply to the persistence unit - delimited-identifiers - Used to treat database identifiers as delimited identifiers. - access - Used as the access type for all managed classes in the persistence unit - cascade-persist - Adds cascade-persist to the set of cascade options in all entity relationships of the persistence unit - entity-listeners - List of default entity listeners to be invoked on each entity in the persistence unit. @@ -203,14 +218,15 @@ + - + - + @@ -222,87 +238,205 @@ - + - javax.persistence.AccessType enum values - - - - - - - + See jakarta.persistence.Entity + Defines the settings and mappings for an entity. Is allowed to be + sparsely populated and used in conjunction with the annotations. + Alternatively, the metadata-complete attribute can be used to + indicate that no annotations on the entity class (and its fields + or properties) are to be processed. If this is the case then + the defaulting rules for the entity and its subelements will + be recursively applied. - + @Target(TYPE) @Retention(RUNTIME) + public @interface Entity { + String name() default ""; + } - - - - Hibernate specific "any" mapping, which is a polymorphic association to any different - tables based on a discriminator - - the given identifier type. The first listed column is a VARCHAR column - holding the name of the class (for that row). - - - - - - - - - - - - - - - - - - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + - + - com.acme.Employee - ]]> + + See `@org.hibernate.annotations.PolymorphismType` + See `@org.hibernate.annotations.Polymorphism` + - - - + + + + + + + + + + See `@org.hibernate.annotations.OptimisticLockType` + See `@org.hibernate.annotations.OptimisticLocking` + + + + + + + + + + + + + + See `@org.hibernate.annotations.TenantId` + See `@org.hibernate.annotations.TenantId` + + + + + - + + + Entity-defined attributes + This element contains the entity field or property mappings. It may be sparsely populated to include only a subset of the fields or properties. If metadata-complete for the entity is true then the remainder of the attributes will be defaulted according to the default rules. + @@ -311,7 +445,8 @@ - + + @@ -321,205 +456,76 @@ - - + + + + - - + - @javax.persistence.AssociationOverride + See `org.hibernate.annotations.GenerationTime` + See `org.hibernate.tuple.GenerationTiming` + See `@org.hibernate.annotations.Generated` - - - - - - - - - - - - - - - - - - - - @javax.persistence.AttributeOverride - - - - - - - - - - - + + + + + + - See javax.persistence.Basic + See `@jakarta.persistence.Basic` + See `@jakarta.persistence.Lob` + See `@jakarta.persistence.Temporal` + See `@jakarta.persistence.Enumerated` + See `@jakarta.persistence.Convert` + See `@org.hibernate.annotations.Nationalized` + See `@org.hibernate.annotations.OptimisticLock` + See `@org.hibernate.annotations.AttributeAccessor` - - + - + - + - - - - - - - - - - - + + + + - + - - - - - - Corresponds to the org.hibernate.annotations.Cache annotation. - - Used to specify Hibernate-specific extra control over the caching - of entity and collection state. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - org.hibernate.CacheMode enum values - - - - - - - - - - - - - - - - - - javax.persistence.CascadeType enum values - - - - - - - - - - - - - - - - - - - org.hibernate.annotations.CascadeType enum values - - - - - - - - - - - - - - - - - - - - - - org.hibernate.annotations.OnDeleteAction enum values - - - - - - - - - @CollectionTable annotation + See `@jakarta.persistence.CollectionTable` @@ -527,102 +533,83 @@ + - + + + + + + See `@jakarta.persistence.ColumnResult` + + + + + - + - See the javax.persistence.Column annotation. + See `jakarta.persistence.ConstraintMode` - - - - - - - - - - - - - - - - - - - - + + + + + + + + + - + + - Corresponds to the javax.persistence.Convert annotation + See `@jakarta.persistence.ConstructorResult` - + - - - - + - - - - - - - Corresponds to the javax.persistence.Converter annotation - - - - - - - - - - - @DiscriminatorColumn annotation + See `@jakarta.persistence.DiscriminatorColumn` + See `@org.hibernate.annotations.DiscriminatorOptions` - - + + - - javax.persistence.DiscriminatorType enum values + See `jakarta.persistence.DiscriminatorType` @@ -632,40 +619,43 @@ - - - @Target({TYPE}) @Retention(RUNTIME) - public @interface DiscriminatorValue { - String value(); - } - + See `jakarta.persistence.DiscriminatorValue - - Corresponds to the @ElementCollection annotation + See `jakarta.persistence.ElementCollection` + See `jakarta.persistence.OrderBy` + See `jakarta.persistence.OrderColumn` + See `@org.hibernate.annotations.AttributeAccessor` + See `@org.hibernate.annotations.OptimisticLock` + See `@org.hibernate.annotations.SortComparator` + See `@org.hibernate.annotations.SortNatural` + See `@jakarta.persistence.Lob` + See `@jakarta.persistence.Temporal` + See `@jakarta.persistence.Enumerated` + See `@jakarta.persistence.Convert` + See `@org.hibernate.annotations.Nationalized` - - + @@ -673,7 +663,6 @@ - @@ -691,6 +680,7 @@ + @@ -701,7 +691,7 @@ - + @@ -711,31 +701,22 @@ - - + + - - See javax.persistence.Embeddable - - Defines the settings and mappings for embeddable objects. - - Again, with metadata-complete=false the mapping is used in - conjunction with annotations. Alternatively, metadata-complete=true - can be used to indicate that no annotations are to be processed - in the class. If this is the case then the defaulting rules will - be recursively applied. + See `@jakarta.persistence.Embeddable` @@ -747,10 +728,14 @@ - + + + Describes the features available for mapping attributes of embeddables + + @@ -760,6 +745,10 @@ + + + + @@ -768,11 +757,12 @@ - Corresponds to the javax.persistence.Embedded annotation + See `@jakarta.persistence.Embedded` + See `@org.hibernate.annotations.AttributeAccessor` + See `@org.hibernate.annotations.OptimisticLock` - @@ -780,7 +770,7 @@ - + @@ -788,7 +778,8 @@ - Corresponds to the javax.persistence.EmbeddedId annotation + See `@jakarta.persistence.EmbeddedId` + See `@org.hibernate.annotations.AttributeAccessor` @@ -799,194 +790,25 @@ - - - - - - - See javax.persistence.Entity - - Defines the settings and mappings for an entity. - - May be used in 2 ways: - 1. sparsely populated (metadata-complete=false) and used in - conjunction with the annotations. - 2. as complete self-contained metadata (metadata-complete=true) - indicating that no annotations on the entity class (and its fields - or properties) are to be processed. If this is the case then - the defaulting rules for the entity and its subelements will - be recursively applied. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Corresponds to the JPA javax.persistence.EntityListeners annotation - - - - - - - - - Corresponds to the JPA javax.persistence.EntityListener annotation - - Defines an entity listener to be invoked at lifecycle events for - the entities that list this listener. + See `@jakarta.persistence.PrePersist` + See `@jakarta.persistence.PreRemove` + See `@jakarta.persistence.PreUpdate` + See `@jakarta.persistence.PostPersist` + See `@jakarta.persistence.PostRemove` + See `@jakarta.persistence.PostUpdate` + See `@jakarta.persistence.PostLoad` - + @@ -996,13 +818,41 @@ + + + + + + See `@jakarta.persistence.EntityListeners` + + + + + + + + + + + + + See `@jakarta.persistence.EntityResult` + + + + + + + + + - javax.persistence.EnumType enum values + See `jakarta.persistence.EnumType` @@ -1011,25 +861,23 @@ - - Corresponds to the javax.persistence.Enumerated annotation. + See `@jakarta.persistence.Enumerated` - - javax.persistence.FetchType enum values + See `jakarta.persistence.FetchType` @@ -1038,121 +886,81 @@ - - + - org.hibernate.annotations.FetchMode enum values + See `@jakarta.persistence.FieldResult` - - - - - - - - - - - - - - org.hibernate.FlushMode enum values - - - - - - - - - + + + - @ForeignKey annotation + See `@jakarta.persistence.ForeignKey` - + - - - See the javax.persistence.GeneratedValue annotation + See `@jakarta.persistence.GeneratedValue` + + - javax.persistence.GenerationType rnum values - - todo : add custom ones like INCREMENT, UUID, etc + See `jakarta.persistence.GenerationType` + - - - - - - - Hibernate-specific element used declare and short-name custom - org.hibernate.id.IdentifierGenerator implementations - - - - - - - - Corresponds to the javax.persistence.Id annotation + See `@jakarta.persistence.Id` + See `@org.hibernate.annotations.AttributeAccessor` - - - - - + + + - - - + @@ -1160,78 +968,67 @@ - - Corresponds to the javax.persistence.IdClass annotation + See `@jakarta.persistence.IdClass` - - Corresponds to @Index annotation + See `jakarta.persistence.Index` - - - - Corresponds to the @Inheritance annotation + See `@jakarta.persistence.Inheritance` - - Corresponds to the JPA InheritanceType enumeration values + Hibernate's UNION_SUBCLASS - - todo : make a singular enum to cover these + See `jakarta.persistence.InheritanceType - - - - + + + - - JoinColumn annotation + See `@jakarta.persistence.JoinColumn` - @@ -1242,17 +1039,16 @@ - - @JoinTable annotation + See `@jakarta.persistence.JoinTable` - + @@ -1264,30 +1060,27 @@ - - - Corresponds to javax.persistence.Lob (marker) annotation + See `jakarta.persistence.Lob` - - javax.persistence.LockModeType enum values + See `javax.persistence.LockModeType` @@ -1299,62 +1092,27 @@ + - - - - - - Hibernate specific "any" mapping (plural form), which is a polymorphic association to any different - tables based on a discriminator. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @ManyToMany annotation + See `@jakarta.persistence.ManyToMany` + + See `@org.hibernate.annotations.SortComparator` + See `@org.hibernate.annotations.SortNatural` + See `@org.hibernate.annotations.AttributeAccessor` - - - + + @@ -1364,7 +1122,6 @@ - @@ -1381,94 +1138,80 @@ - - - - + - - - - - Corresponds to the @ManyToOne annotation + See `@jakarta.persistence.ManyToOne` + + See `@org.hibernate.annotations.AttributeAccessor` + See `@org.hibernate.annotations.OnDelete - - - - - + - - - @javax.persistence.MapKey + See `@jakarta.persistence.MapKey` - - @javax.persistence.MapKeyClass + See `@jakarta.persistence.MapKeyClass` - - - @javax.persistence.MapKeyColumn + See `@jakarta.persistence.MapKeyColumn` - @@ -1481,16 +1224,14 @@ - - @javax.persistence.MapKeyJoinColumn + See `@jakarta.persistence.MapKeyJoinColumn` - @@ -1507,22 +1248,13 @@ - See javax.persistence.MappedSuperclass - - Defines the settings and mappings for a mapped superclass. - - May be used in 2 ways: - 1. sparsely populated (metadata-complete=false) and used in - conjunction with the annotations. - 2. as complete self-contained metadata (metadata-complete=true) - indicating that no annotations are to be processed. If this is - the case then the defaulting rules will be recursively applied. + See `@jakarta.persistence.MappedSuperclass` - + @@ -1533,6 +1265,7 @@ + @@ -1542,72 +1275,95 @@ - - + - Hibernate-specific element used to describe the meta-value (discriminator) - mapping for ANY associations. + + @Target({}) @Retention(RUNTIME) + public @interface NamedAttributeNode { + String value(); + String subgraph() default ""; + String keySubgraph() default ""; + } + - - - + + + - - @NamedEntityGraph annotation + + @Target({TYPE}) @Retention(RUNTIME) + public @interface NamedEntityGraph { + String name() default ""; + NamedAttributeNode[] attributeNodes() default {}; + boolean includeAllAttributes() default false; + NamedSubgraph[] subgraphs() default {}; + NamedSubGraph[] subclassSubgraphs() default {}; + } + - - - - + + + - - - - - @NamedAttributeNode annotation - - - - - - - - - - - - @NamedSubgraph annotation - - - - - - - - - - - - + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface NamedNativeQuery { + String name(); + String query(); + QueryHint[] hints() default {}; + Class resultClass() default void.class; + String resultSetMapping() default ""; //named SqlResultSetMapping + } + + + + + + + + + + + + + + + + + + + Common Hibernate specific extensions available for named query definitions. @@ -1621,7 +1377,7 @@ - + @@ -1632,382 +1388,6 @@ - - - - Mix of @javax.persistence.NamedNativeQuery and @org.hibernate.annotations.NamedNativeQuery - - - - - - - - - - - - - - - - - - - - - - Mix of @javax.persistence.NamedQuery and @org.hibernate.annotations.NamedQuery - - - - - - - - - - - - - - - - - - - - Corresponds to the javax.persistence.NamedStoredProcedureQuery annotation - - - - - - - - - - - - - - - - - - - Corresponds to javax.persistence.StoredProcedureParameter annotation - - - - - - - - - - - - - - - - javax.persistence.ParameterMode enum values - - - - - - - - - - - - - - - - - - @OneToMany annotation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Corresponds to the @OneToOne annotation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @javax.persistence.OrderBy annotation - - - - - - - - - - - - - @javax.persistence.OrderColumn annotation - - - - - - - - - - - - - - - - - Corresponds to the javax.persistence.PostLoad annotation - - - - - - - - - - - - - - - - - Corresponds to the javax.persistence.PostPersist annotation - - - - - - - - - - - - - - - - - Corresponds to the javax.persistence.PostRemove annotation - - - - - - - - - - - - - - - - - Corresponds to the javax.persistence.PostUpdate annotation - - - - - - - - - - - - - - - - - Corresponds to the javax.persistence.PrePersist annotation - - - - - - - - - - - - - - - - - Corresponds to the javax.persistence.PreRemove annotation - - - - - - - - - - - - - - - - - Corresponds to the javax.persistence.PreUpdate annotation - - - - - - - - - - - - - - - - - @PrimaryKeyJoinColumn annotation - - - - - - - - - - - - - - - @javax.persistence.QueryHint - - - - - - - - - - - @@ -2025,27 +1405,442 @@ - + - @javax.persistence.SecondaryTable + + @Target({TYPE}) @Retention(RUNTIME) + public @interface NamedQuery { + String name(); + String query(); + LockModeType lockMode() default NONE; + QueryHint[] hints() default {}; + } + - - - - - - - - + + + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface NamedStoredProcedureQuery { + String name(); + String procedureName(); + StoredProcedureParameter[] parameters() default {}; + Class[] resultClasses() default {}; + String[] resultSetMappings() default{}; + QueryHint[] hints() default {}; + } + + + + + + + + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface StoredProcedureParameter { + String name() default ""; + ParameterMode mode() default ParameterMode.IN; + Class type(); + } + + + + + + + + + + + + + + + + + + + public enum ParameterMode { IN, INOUT, OUT, REF_CURSOR}; + + + + + + + + + + + + + + + + + + + @Target({}) @Retention(RUNTIME) + public @interface NamedSubgraph { + String name(); + Class type() default void.class; + NamedAttributeNode[] attributeNodes(); + } + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface OneToMany { + Class targetEntity() default void.class; + CascadeType[] cascade() default {}; + FetchType fetch() default LAZY; + String mappedBy() default ""; + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface OneToOne { + Class targetEntity() default void.class; + CascadeType[] cascade() default {}; + FetchType fetch() default EAGER; + boolean optional() default true; + String mappedBy() default ""; + boolean orphanRemoval() default false; + } + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface OrderBy { + String value() default ""; + } + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface OrderColumn { + String name() default ""; + boolean nullable() default true; + boolean insertable() default true; + boolean updatable() default true; + String columnDefinition() default ""; + } + + + + + + + + + + + + + + + + + + @Target({METHOD}) @Retention(RUNTIME) + public @interface PostLoad {} + + + + + + + + + + + + + + + + @Target({METHOD}) @Retention(RUNTIME) + public @interface PostPersist {} + + + + + + + + + + + + + + + + @Target({METHOD}) @Retention(RUNTIME) + public @interface PostRemove {} + + + + + + + + + + + + + + + + @Target({METHOD}) @Retention(RUNTIME) + public @interface PostUpdate {} + + + + + + + + + + + + + + + + @Target({METHOD}) @Retention(RUNTIME) + public @interface PrePersist {} + + + + + + + + + + + + + + + + @Target({METHOD}) @Retention(RUNTIME) + public @interface PreRemove {} + + + + + + + + + + + + + + + + @Target({METHOD}) @Retention(RUNTIME) + public @interface PreUpdate {} + + + + + + + + + + + + + + + + @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME) + public @interface PrimaryKeyJoinColumn { + String name() default ""; + String referencedColumnName() default ""; + String columnDefinition() default ""; + } + + + + + + + + + + + + + + + @Target({}) @Retention(RUNTIME) + public @interface QueryHint { + String name(); + String value(); + } + + + + + + + + @@ -2054,14 +1849,22 @@ - @javax.persistence.SequenceGenerator + + @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME) + public @interface SequenceGenerator { + String name(); + String sequenceName() default ""; + String catalog() default ""; + String schema() default ""; + int initialValue() default 1; + int allocationSize() default 50; + } + - - @@ -2070,110 +1873,68 @@ - - @javax.persistence.SqlResultSetMapping + + @Target({TYPE}) @Retention(RUNTIME) + public @interface SqlResultSetMapping { + String name(); + EntityResult[] entities() default {}; + ConstructorResult[] classes() default{}; + ColumnResult[] columns() default {}; + } + - - - - + + + - - - - - - @javax.persistence.ColumnResult - - - - - - - - - - - - @javax.persistence.ConstructorResult - - - - - - - - - - - - - - - @javax.persistence.EntityResult - - - - - - - - - - - - - - - - @javax.persistence.FieldResult - - - - - - - - - - - - - - - - @javax.persistence.Table + + @Target({TYPE}) @Retention(RUNTIME) + public @interface Table { + String name() default ""; + String catalog() default ""; + String schema() default ""; + UniqueConstraint[] uniqueConstraints() default {}; + Index[] indexes() default {}; + } + - - + - - + + + + See `@org.hibernate.annotations.Comment` + See `@org.hibernate.annotations.Check` + + @@ -2183,20 +1944,68 @@ - + - @javax.persistence.TableGenerator + + @Target({TYPE}) @Retention(RUNTIME) + public @interface SecondaryTable { + String name(); + String catalog() default ""; + String schema() default ""; + PrimaryKeyJoinColumn[] pkJoinColumns() default {}; + UniqueConstraint[] uniqueConstraints() default {}; + Index[] indexes() default {}; + } + - - - + + + + + + + + + + + + + + + + + + + @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME) + public @interface TableGenerator { + String name(); + String table() default ""; + String catalog() default ""; + String schema() default ""; + String pkColumnName() default ""; + String valueColumnName() default ""; + String pkColumnValue() default ""; + int initialValue() default 0; + int allocationSize() default 50; + UniqueConstraint[] uniqueConstraints() default {}; + Indexes[] indexes() default {}; + } + + + + + + + + + @@ -2208,25 +2017,34 @@ - - @javax.persistence.Temporal + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface Temporal { + TemporalType value(); + } + - - javax.persistence.TemporalType enum values + + public enum TemporalType { + DATE, // java.sql.Date + TIME, // java.sql.Time + TIMESTAMP // java.sql.Timestamp + } + @@ -2236,93 +2054,95 @@ - - @javax.persistence.Transient + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface Transient {} + - - @javax.persistence.UniqueConstraint + + @Target({}) @Retention(RUNTIME) + public @interface UniqueConstraint { + String name() default ""; + String[] columnNames(); + } + - - + - - - @javax.persistence.Version + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface Version {} + - - - - + - - - - - element defines a single path to which the fetch - refers, as well as the style of fetch to apply. The 'root' of the - path is different depending upon the context in which the - containing occurs; within a element, - the entity-name of the containing class mapping is assumed... - ]]> - - - - - - - - - - - - - - - - - - + - + + + + + + + + + + + + + + + + + + + + + + Specifies a filter definition. After definition, a filter @@ -2372,23 +2192,46 @@ - + - + - + + + element defines a single path to which the fetch + refers, as well as the style of fetch to apply. The 'root' of the + path is different depending upon the context in which the + containing occurs; within a element, + the entity-name of the containing class mapping is assumed... + ]]> + + + + + + + + + + + + + + - + + - + Names a org.hibernate.id.IdentifierGenerator implementation (class attribute) @@ -2403,43 +2246,90 @@ - + - Corresponds to the org.hibernate.annotations.Parameter annotation + Corresponds to the org.hibernate.annotations.Cache annotation. + + Used to specify Hibernate-specific extra control over the caching + of entity and collection state. - - - - - + + + - - - - + - - - + + - - - - - - - + + + + org.hibernate.cache.spi.access.AccessType enum values + + + + + + + + + + + + + + + + org.hibernate.CacheMode enum values + + + + + + + + + + + + + + + + + + - + + + + See `@org.hibernate.annotations.TenantId` + + + + + + + + + + + + + + + + The loader element allows specification of a named query to be used for fetching @@ -2452,31 +2342,175 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + This element determines how the persistence provider accesses the + state of an entity or embedded object. + + + + + + + + + + + + + + + + + @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME) + public @interface AssociationOverride { + String name(); + JoinColumn[] joinColumns() default{}; + JoinTable joinTable() default @JoinTable; + } + + + - - - + + + + + + + - - + - + + + + + @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME) + public @interface AttributeOverride { + String name(); + Column column(); + } + + + + + + + + + + + + + + + + + See `@org.hibernate.annotations.NaturalId` + + + + + + + + + + + + + + + + + + + + + + See `@org.hibernate.annotations.Any` + + + + + + + + + + + + + + + + + + Describes the discriminator of a discriminated association (any, many-to-any), + including the mapping of discriminator values to matching entity name + + + + + + + + + + + + + Describes the "foreign key" of a discriminated association (any, many-to-any). + + + + + + + + + tags from hbm.xml dtd; renamed here for - self-documentation. This information is intended mainly for tooling. + Maps a discriminator value to its corresponding entity name. E.g.: + + com.acme.Employee ]]> - - + @@ -2484,60 +2518,192 @@ - + - Corresponds to the org.hibernate.annotations.Type annotation, naming - a org.hibernate.type.* or org.hibernate.usertype.* implementation to use. - - name - names the type implementation class - - param - If the type is able to accept parameters (implementation stems from - org.hibernate.type.Type, org.hibernate.type.CollectionType, or - org.hibernate.usertype.ParameterizedType) the specified parameters will be - passed to the type instance after instantiation. + See `@org.hibernate.annotations.ManyToAny` + - + + + + + + + - - - - - - - - - - - - - - - + - A natural-id element allows declaration of unique business key + See `@jakarta.persistence.CascadeType` + See `@org.hibernate.annotations.Cascade` - - - - + + + + + + + + + + - - + + + + + + + See `@jakarta.persistence.Column` + See `@org.hibernate.annotations.Comment` + See `@org.hibernate.annotations.Check` + See `@org.hibernate.annotations.ColumnDefault` + See `@org.hibernate.annotations.ColumnTransformer` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + See `@jakarta.persistence.Convert` + + + + + + + + + + + + + + + + + See `@jakarta.persistence.Converter` + See `@jakarta.persistence.AttributeConverter + + + + + + + + + + + + + + + + See `@org.hibernate.annotations.Nationalized` + + + + + + + + + + + + See `org.hibernate.annotations.OnDeleteAction` enum + + + + + + + + + + + + + + + + org.hibernate.FetchMode enum values + + + + + + + + + + + + + + + org.hibernate.FetchMode enum values + + + + + + + + + + + + + + + + org.hibernate.FlushMode enum values + + + + + + + + \ No newline at end of file diff --git a/hibernate-core/src/main/xjb/hbm-mapping-bindings.xjb b/hibernate-core/src/main/xjb/hbm-mapping-bindings.xjb index be27ec047f..2ba1363741 100644 --- a/hibernate-core/src/main/xjb/hbm-mapping-bindings.xjb +++ b/hibernate-core/src/main/xjb/hbm-mapping-bindings.xjb @@ -89,6 +89,10 @@ + + org.hibernate.boot.jaxb.spi.BindableMappingDescriptor + + org.hibernate.boot.jaxb.hbm.spi.ToolingHintContainer diff --git a/hibernate-core/src/main/xjb/mapping-bindings.xjb b/hibernate-core/src/main/xjb/mapping-bindings.xjb index 3cfd6b503c..e77f75253e 100644 --- a/hibernate-core/src/main/xjb/mapping-bindings.xjb +++ b/hibernate-core/src/main/xjb/mapping-bindings.xjb @@ -6,9 +6,9 @@ extensionBindingPrefixes="inheritance" version="3.0"> - + - + @@ -17,174 +17,376 @@ + + org.hibernate.boot.jaxb.spi.BindableMappingDescriptor + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.hibernate.boot.jaxb.mapping.EntityOrMappedSuperclass + + + + org.hibernate.boot.jaxb.mapping.ManagedType + + + + org.hibernate.boot.jaxb.mapping.EntityOrMappedSuperclass + + + + org.hibernate.boot.jaxb.mapping.AttributesContainer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.hibernate.boot.jaxb.mapping.AttributesContainer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.hibernate.boot.jaxb.mapping.PersistentAttribute + + + + org.hibernate.boot.jaxb.mapping.PersistentAttribute + + + + org.hibernate.boot.jaxb.mapping.PersistentAttribute + + + + org.hibernate.boot.jaxb.mapping.PersistentAttribute + + + + org.hibernate.boot.jaxb.mapping.PersistentAttribute + + + + org.hibernate.boot.jaxb.mapping.ToOneAttribute + + + + org.hibernate.boot.jaxb.mapping.ToOneAttribute + + + + org.hibernate.boot.jaxb.mapping.DiscriminatedAssociation + + + + org.hibernate.boot.jaxb.mapping.CollectionAttribute + + + + org.hibernate.boot.jaxb.mapping.CollectionAttribute + org.hibernate.boot.jaxb.mapping.AssociationAttribute + + + + org.hibernate.boot.jaxb.mapping.CollectionAttribute + org.hibernate.boot.jaxb.mapping.AssociationAttribute + + + + org.hibernate.boot.jaxb.mapping.DiscriminatedAssociation + + + + org.hibernate.boot.jaxb.mapping.DiscriminatedAssociation.Discriminator + + + + + + + org.hibernate.boot.jaxb.mapping.DiscriminatorMapping + + + + + + + + org.hibernate.boot.jaxb.mapping.DiscriminatedAssociation.Key + + + + + + + org.hibernate.boot.jaxb.mapping.SchemaAware + + + org.hibernate.boot.jaxb.mapping.SchemaAware + + + org.hibernate.boot.jaxb.mapping.SchemaAware + + + org.hibernate.boot.jaxb.mapping.SchemaAware + + + org.hibernate.boot.jaxb.mapping.SchemaAware + + + org.hibernate.boot.jaxb.mapping.SchemaAware + + + + + + + + + org.hibernate.boot.jaxb.mapping.LifecycleCallbackContainer + + + + org.hibernate.boot.jaxb.mapping.LifecycleCallback + + + org.hibernate.boot.jaxb.mapping.LifecycleCallback + + + org.hibernate.boot.jaxb.mapping.LifecycleCallback + + + org.hibernate.boot.jaxb.mapping.LifecycleCallback + + + org.hibernate.boot.jaxb.mapping.LifecycleCallback + + + org.hibernate.boot.jaxb.mapping.LifecycleCallback + + + org.hibernate.boot.jaxb.mapping.LifecycleCallback + + + + + + + + + + + + + parseMethod="org.hibernate.boot.jaxb.mapping.marshall.AccessTypeMarshalling.fromXml" + printMethod="org.hibernate.boot.jaxb.mapping.marshall.AccessTypeMarshalling.toXml" /> + + + + + + + + + parseMethod="org.hibernate.boot.jaxb.mapping.marshall.DiscriminatorTypeMarshalling.fromXml" + printMethod="org.hibernate.boot.jaxb.mapping.marshall.DiscriminatorTypeMarshalling.toXml" /> + parseMethod="org.hibernate.boot.jaxb.mapping.marshall.EnumTypeMarshalling.fromXml" + printMethod="org.hibernate.boot.jaxb.mapping.marshall.EnumTypeMarshalling.toXml" /> + parseMethod="org.hibernate.boot.jaxb.mapping.marshall.FetchTypeMarshalling.fromXml" + printMethod="org.hibernate.boot.jaxb.mapping.marshall.FetchTypeMarshalling.toXml" /> + + + + + parseMethod="org.hibernate.boot.jaxb.mapping.marshall.LockModeTypeMarshalling.fromXml" + printMethod="org.hibernate.boot.jaxb.mapping.marshall.LockModeTypeMarshalling.toXml" /> + + + + + parseMethod="org.hibernate.boot.jaxb.mapping.marshall.ParameterModeMarshalling.fromXml" + printMethod="org.hibernate.boot.jaxb.mapping.marshall.ParameterModeMarshalling.toXml" /> + + + + + + + + + + + + + parseMethod="org.hibernate.boot.jaxb.mapping.marshall.TemporalTypeMarshalling.fromXml" + printMethod="org.hibernate.boot.jaxb.mapping.marshall.TemporalTypeMarshalling.toXml" /> + parseMethod="org.hibernate.boot.jaxb.mapping.marshall.InheritanceTypeMarshalling.fromXml" + printMethod="org.hibernate.boot.jaxb.mapping.marshall.InheritanceTypeMarshalling.toXml" /> + parseMethod="org.hibernate.boot.jaxb.mapping.marshall.GenerationTypeMarshalling.fromXml" + printMethod="org.hibernate.boot.jaxb.mapping.marshall.GenerationTypeMarshalling.toXml" /> + + + + + parseMethod="org.hibernate.boot.jaxb.mapping.marshall.ConstraintModeMarshalling.fromXml" + printMethod="org.hibernate.boot.jaxb.mapping.marshall.ConstraintModeMarshalling.toXml" /> - - - org.hibernate.boot.jaxb.mapping.spi.SchemaAware - - - org.hibernate.boot.jaxb.mapping.spi.SchemaAware - - - org.hibernate.boot.jaxb.mapping.spi.SchemaAware - - - org.hibernate.boot.jaxb.mapping.spi.SchemaAware - - - org.hibernate.boot.jaxb.mapping.spi.SchemaAware - - - org.hibernate.boot.jaxb.mapping.spi.SchemaAware - - - - org.hibernate.boot.jaxb.mapping.spi.ManagedType - org.hibernate.boot.jaxb.mapping.spi.EntityOrMappedSuperclass - org.hibernate.boot.jaxb.mapping.spi.LifecycleCallbackContainer - - - org.hibernate.boot.jaxb.mapping.spi.ManagedType - - - org.hibernate.boot.jaxb.mapping.spi.ManagedType - org.hibernate.boot.jaxb.mapping.spi.EntityOrMappedSuperclass - org.hibernate.boot.jaxb.mapping.spi.LifecycleCallbackContainer - - - - org.hibernate.boot.jaxb.mapping.spi.LifecycleCallbackContainer - - - - org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute - - - org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute - - - org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute - - - org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute - org.hibernate.boot.jaxb.mapping.spi.FetchableAttribute - org.hibernate.boot.jaxb.mapping.spi.AssociationAttribute - - - org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute - org.hibernate.boot.jaxb.mapping.spi.CollectionAttribute - org.hibernate.boot.jaxb.mapping.spi.AssociationAttribute - - - org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute - org.hibernate.boot.jaxb.mapping.spi.FetchableAttribute - org.hibernate.boot.jaxb.mapping.spi.AssociationAttribute - - - org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute - - - org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute - - - org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute - org.hibernate.boot.jaxb.mapping.spi.CollectionAttribute - org.hibernate.boot.jaxb.mapping.spi.AssociationAttribute - - - org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute - org.hibernate.boot.jaxb.mapping.spi.CollectionAttribute - - - - org.hibernate.boot.jaxb.mapping.spi.LifecycleCallback - - - org.hibernate.boot.jaxb.mapping.spi.LifecycleCallback - - - org.hibernate.boot.jaxb.mapping.spi.LifecycleCallback - - - org.hibernate.boot.jaxb.mapping.spi.LifecycleCallback - - - org.hibernate.boot.jaxb.mapping.spi.LifecycleCallback - - - org.hibernate.boot.jaxb.mapping.spi.LifecycleCallback - - - org.hibernate.boot.jaxb.mapping.spi.LifecycleCallback - - - - org.hibernate.boot.jaxb.mapping.spi.AttributesContainer - - - org.hibernate.boot.jaxb.mapping.spi.AttributesContainer - + diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java index 92ef4a58a1..03cf3cf997 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java @@ -2,29 +2,82 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ package org.hibernate.orm.test.annotations.reflection; -import org.hibernate.annotations.Columns; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; -import org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenAnnotationReader; -import org.hibernate.cfg.annotations.reflection.internal.XMLContext; -import org.hibernate.orm.test.internal.util.xml.XMLMappingHelper; - -import org.hibernate.testing.boot.BootstrapContextImpl; -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.hibernate.testing.TestForIssue; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import jakarta.persistence.*; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; -import static org.junit.Assert.*; +import org.hibernate.annotations.Columns; +import org.hibernate.boot.jaxb.mapping.JaxbEntityMappings; +import org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenAnnotationReader; +import org.hibernate.cfg.annotations.reflection.internal.XMLContext; +import org.hibernate.orm.test.internal.util.xml.XMLMappingHelper; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.boot.BootstrapContextImpl; +import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import jakarta.persistence.AssociationOverrides; +import jakarta.persistence.AttributeOverrides; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Converts; +import jakarta.persistence.DiscriminatorColumn; +import jakarta.persistence.DiscriminatorValue; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Embedded; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.ExcludeDefaultListeners; +import jakarta.persistence.ExcludeSuperclassListeners; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; +import jakarta.persistence.JoinColumns; +import jakarta.persistence.JoinTable; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.MapKey; +import jakarta.persistence.MappedSuperclass; +import jakarta.persistence.NamedNativeQueries; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.OrderBy; +import jakarta.persistence.PostLoad; +import jakarta.persistence.PostPersist; +import jakarta.persistence.PrePersist; +import jakarta.persistence.PrimaryKeyJoinColumn; +import jakarta.persistence.PrimaryKeyJoinColumns; +import jakarta.persistence.SecondaryTable; +import jakarta.persistence.SecondaryTables; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.SqlResultSetMappings; +import jakarta.persistence.Table; +import jakarta.persistence.TableGenerator; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; +import jakarta.persistence.Transient; +import jakarta.persistence.Version; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; /** * @author Emmanuel Bernard diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/reflection/XMLContextTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/reflection/XMLContextTest.java index c583e78736..1694016863 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/reflection/XMLContextTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/reflection/XMLContextTest.java @@ -2,11 +2,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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ package org.hibernate.orm.test.annotations.reflection; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; +import org.hibernate.boot.jaxb.mapping.JaxbEntityMappings; import org.hibernate.cfg.annotations.reflection.internal.XMLContext; import org.hibernate.orm.test.internal.util.xml.XMLMappingHelper; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/xml/ejb3/Ejb3XmlTestCase.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/xml/ejb3/Ejb3XmlTestCase.java index 8ed9b4c883..fee1820d4f 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/xml/ejb3/Ejb3XmlTestCase.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/xml/ejb3/Ejb3XmlTestCase.java @@ -2,7 +2,7 @@ * 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 . + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. */ package org.hibernate.orm.test.annotations.xml.ejb3; @@ -10,14 +10,13 @@ import java.io.InputStream; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; +import org.hibernate.boot.jaxb.mapping.JaxbEntityMappings; import org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenAnnotationReader; import org.hibernate.cfg.annotations.reflection.internal.XMLContext; import org.hibernate.orm.test.internal.util.xml.XMLMappingHelper; import org.hibernate.testing.boot.BootstrapContextImpl; import org.hibernate.testing.junit4.BaseUnitTestCase; - import org.junit.After; import org.junit.Before; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/jaxb/mapping/BasicMappingJaxbTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/jaxb/mapping/BasicMappingJaxbTests.java new file mode 100644 index 0000000000..d5511d1168 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/jaxb/mapping/BasicMappingJaxbTests.java @@ -0,0 +1,63 @@ +/* + * 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.boot.jaxb.mapping; + +import java.io.IOException; +import java.io.InputStream; +import javax.xml.stream.XMLEventFactory; +import javax.xml.stream.XMLEventReader; + +import org.hibernate.boot.jaxb.internal.stax.MappingEventReader; +import org.hibernate.boot.jaxb.mapping.JaxbEntityMappings; +import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; +import org.hibernate.boot.xsd.MappingXsdSupport; + +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; +import org.junit.jupiter.api.Test; + +import jakarta.xml.bind.JAXBContext; +import jakarta.xml.bind.JAXBException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hibernate.orm.test.boot.jaxb.mapping.JaxbHelper.withStaxEventReader; + +/** + * @author Steve Ebersole + */ +@ServiceRegistry +public class BasicMappingJaxbTests { + @Test + public void simpleUnifiedJaxbTest(ServiceRegistryScope scope) { + scope.withService( ClassLoaderService.class, (cls) -> { + verify( "xml/jaxb/mapping/basic/unified.xml", cls, scope ); + verify( "xml/jaxb/mapping/basic/orm.xml", cls, scope ); + } ); + } + + private void verify(String resourceName, ClassLoaderService cls, ServiceRegistryScope scope) { + try ( final InputStream inputStream = cls.locateResourceStream( resourceName ) ) { + withStaxEventReader( inputStream, cls, (staxEventReader) -> { + final XMLEventFactory xmlEventFactory = XMLEventFactory.newInstance(); + final XMLEventReader reader = new MappingEventReader( staxEventReader, xmlEventFactory ); + try { + final JAXBContext jaxbCtx = JAXBContext.newInstance( org.hibernate.boot.jaxb.mapping.JaxbEntityMappings.class ); + final JaxbEntityMappings entityMappings = JaxbHelper.VALIDATING.jaxb( reader, MappingXsdSupport._310.getSchema(), jaxbCtx ); + assertThat( entityMappings ).isNotNull(); + assertThat( entityMappings.getEntities() ).hasSize( 1 ); + } + catch (JAXBException e) { + throw new RuntimeException( "Error during JAXB processing", e ); + } + } ); + } + catch (IOException e) { + throw new RuntimeException( "Error accessing mapping file", e ); + } + + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/jaxb/mapping/CachingOverrideTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/jaxb/mapping/CachingOverrideTest.java new file mode 100644 index 0000000000..54f05646f3 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/jaxb/mapping/CachingOverrideTest.java @@ -0,0 +1,28 @@ +/* + * 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.boot.jaxb.mapping; + +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Steve Ebersole + */ +@DomainModel( annotatedClasses = SimpleEntity.class, xmlMappings = "xml/jaxb/mapping/partial/caching.xml" ) +public class CachingOverrideTest { + @Test + public void verifyMapping(DomainModelScope scope) { + scope.withHierarchy( SimpleEntity.class, (entityDescriptor) -> { + assertThat( entityDescriptor.isCached() ).isTrue(); + assertThat( entityDescriptor.getCacheRegionName() ).isEqualTo( "netherworld" ); + assertThat( entityDescriptor.getCacheConcurrencyStrategy() ).isEqualTo( "transactional" ); + } ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/jaxb/mapping/HbmTransformationJaxbTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/jaxb/mapping/HbmTransformationJaxbTests.java new file mode 100644 index 0000000000..2ff915fba5 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/jaxb/mapping/HbmTransformationJaxbTests.java @@ -0,0 +1,92 @@ +/* + * 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.boot.jaxb.mapping; + +import java.io.IOException; +import java.io.InputStream; +import javax.xml.stream.XMLEventFactory; +import javax.xml.stream.XMLEventReader; + +import org.hibernate.boot.jaxb.Origin; +import org.hibernate.boot.jaxb.SourceType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping; +import org.hibernate.boot.jaxb.hbm.transform.HbmXmlTransformer; +import org.hibernate.boot.jaxb.hbm.transform.UnsupportedFeatureHandling; +import org.hibernate.boot.jaxb.internal.stax.HbmEventReader; +import org.hibernate.boot.jaxb.mapping.JaxbEntity; +import org.hibernate.boot.jaxb.mapping.JaxbEntityMappings; +import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; +import org.hibernate.boot.xsd.MappingXsdSupport; + +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; +import org.junit.jupiter.api.Test; + +import jakarta.xml.bind.JAXBContext; +import jakarta.xml.bind.JAXBException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hibernate.orm.test.boot.jaxb.mapping.JaxbHelper.withStaxEventReader; + +/** + * @author Steve Ebersole + */ +@ServiceRegistry +public class HbmTransformationJaxbTests { + @Test + public void hbmTransformationTest(ServiceRegistryScope scope) { + scope.withService( ClassLoaderService.class, (cls) -> { + verifyHbm( "xml/jaxb/mapping/basic/hbm.xml", cls, scope ); + } ); + } + + private void verifyHbm(String resourceName, ClassLoaderService cls, ServiceRegistryScope scope) { + try ( final InputStream inputStream = cls.locateResourceStream( resourceName ) ) { + withStaxEventReader( inputStream, cls, (staxEventReader) -> { + final XMLEventReader reader = new HbmEventReader( staxEventReader, XMLEventFactory.newInstance() ); + + try { + final JAXBContext jaxbCtx = JAXBContext.newInstance( JaxbHbmHibernateMapping.class ); + final JaxbHbmHibernateMapping hbmMapping = JaxbHelper.VALIDATING.jaxb( reader, MappingXsdSupport.hbmXml.getSchema(), jaxbCtx ); + assertThat( hbmMapping ).isNotNull(); + assertThat( hbmMapping.getClazz() ).hasSize( 1 ); + + final JaxbEntityMappings transformed = HbmXmlTransformer.transform( + hbmMapping, + new Origin( SourceType.RESOURCE, resourceName ), + () -> UnsupportedFeatureHandling.ERROR + ); + + assertThat( transformed ).isNotNull(); + assertThat( transformed.getEntities() ).hasSize( 1 ); + assertThat( transformed.getPackage() ).isEqualTo( "org.hibernate.orm.test.boot.jaxb.mapping" ); + + final JaxbEntity ormEntity = transformed.getEntities().get( 0 ); + assertThat( ormEntity.getName() ).isNull(); + assertThat( ormEntity.getClazz() ).isEqualTo( "SimpleEntity" ); + + assertThat( ormEntity.getAttributes().getId() ).hasSize( 1 ); + assertThat( ormEntity.getAttributes().getBasicAttributes() ).hasSize( 1 ); + assertThat( ormEntity.getAttributes().getEmbeddedAttributes() ).isEmpty(); + assertThat( ormEntity.getAttributes().getOneToOneAttributes() ).isEmpty(); + assertThat( ormEntity.getAttributes().getManyToOneAttributes() ).isEmpty(); + assertThat( ormEntity.getAttributes().getDiscriminatedAssociations() ).isEmpty(); + assertThat( ormEntity.getAttributes().getOneToManyAttributes() ).isEmpty(); + assertThat( ormEntity.getAttributes().getManyToManyAttributes() ).isEmpty(); + assertThat( ormEntity.getAttributes().getPluralDiscriminatedAssociations() ).isEmpty(); + } + catch (JAXBException e) { + throw new RuntimeException( "Error during JAXB processing", e ); + } + } ); + } + catch (IOException e) { + throw new RuntimeException( "Error accessing mapping file", e ); + } + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/jaxb/mapping/JaxbHelper.java b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/jaxb/mapping/JaxbHelper.java new file mode 100644 index 0000000000..8f2e9d9cef --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/jaxb/mapping/JaxbHelper.java @@ -0,0 +1,83 @@ +/* + * 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.boot.jaxb.mapping; + +import java.io.InputStream; +import java.util.function.Consumer; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.validation.Schema; + +import org.hibernate.boot.jaxb.internal.ContextProvidingValidationEventHandler; +import org.hibernate.boot.jaxb.internal.stax.BufferedXMLEventReader; +import org.hibernate.boot.jaxb.internal.stax.LocalXmlResourceResolver; +import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; + +import jakarta.xml.bind.JAXBContext; +import jakarta.xml.bind.JAXBException; +import jakarta.xml.bind.Unmarshaller; + +/** + * @author Steve Ebersole + */ +public class JaxbHelper { + public static final JaxbHelper INSTANCE = new JaxbHelper( false ); + public static final JaxbHelper VALIDATING = new JaxbHelper( true ); + + private final boolean validationEnabled; + + public JaxbHelper(boolean validationEnabled) { + this.validationEnabled = validationEnabled; + } + + public boolean isValidationEnabled() { + return validationEnabled; + } + + public static void withStaxEventReader(InputStream inputStream, ClassLoaderService cls, Consumer action) { + final XMLEventReader reader = createReader( inputStream, cls ); + action.accept( reader ); + try { + reader.close(); + } + catch (XMLStreamException ignore) { + } + } + + private static XMLEventReader createReader(InputStream stream, ClassLoaderService cls) { + final XMLInputFactory staxFactory = XMLInputFactory.newInstance(); + staxFactory.setXMLResolver( new LocalXmlResourceResolver( cls ) ); + + try { + // create a standard StAX reader + final XMLEventReader staxReader = staxFactory.createXMLEventReader( stream ); + // and wrap it in a buffered reader (keeping 100 element sized buffer) + return new BufferedXMLEventReader( staxReader, 100 ); + } + catch (XMLStreamException e) { + throw new RuntimeException( "Unable to create StAX reader", e ); + } + } + + @SuppressWarnings("unchecked") + T jaxb(XMLEventReader reader, Schema xsd, JAXBContext jaxbContext) throws JAXBException { + final ContextProvidingValidationEventHandler handler = new ContextProvidingValidationEventHandler(); + + final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + unmarshaller.setEventHandler( handler ); + + if ( isValidationEnabled() ) { + unmarshaller.setSchema( xsd ); + } + else { + unmarshaller.setSchema( null ); + } + + return (T) unmarshaller.unmarshal( reader ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/jaxb/mapping/PartialJaxbTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/jaxb/mapping/PartialJaxbTests.java new file mode 100644 index 0000000000..7550df5ea2 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/jaxb/mapping/PartialJaxbTests.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.orm.test.boot.jaxb.mapping; + +import org.hibernate.boot.jaxb.Origin; +import org.hibernate.boot.jaxb.SourceType; +import org.hibernate.boot.jaxb.internal.MappingBinder; +import org.hibernate.boot.jaxb.mapping.JaxbEntity; +import org.hibernate.boot.jaxb.mapping.JaxbEntityMappings; +import org.hibernate.boot.jaxb.spi.Binding; +import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; + +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Steve Ebersole + */ +@ServiceRegistry +public class PartialJaxbTests { + @Test + public void cachingTest(ServiceRegistryScope scope) { + final MappingBinder mappingBinder = new MappingBinder( scope.getRegistry() ); + scope.withService( ClassLoaderService.class, (cls) -> { + //noinspection unchecked + final Binding binding = mappingBinder.bind( + cls.locateResourceStream( "xml/jaxb/mapping/partial/caching.xml" ), + new Origin( SourceType.RESOURCE, "xml/jaxb/mapping/partial/caching.xml" ) + ); + + final JaxbEntityMappings entityMappings = binding.getRoot(); + assertThat( entityMappings ).isNotNull(); + assertThat( entityMappings.getEntities() ).hasSize( 1 ); + assertThat( entityMappings.getPackage() ).isEqualTo( "org.hibernate.orm.test.boot.jaxb.mapping" ); + + final JaxbEntity ormEntity = entityMappings.getEntities().get( 0 ); + assertThat( ormEntity.getName() ).isNull(); + assertThat( ormEntity.getClazz() ).isEqualTo( "SimpleEntity" ); + assertThat( ormEntity.isCacheable() ).isTrue(); + assertThat( ormEntity.getCaching() ).isNotNull(); + assertThat( ormEntity.getCaching().getRegion() ).isEqualTo( "netherworld" ); + + assertThat( ormEntity.getAttributes() ).isNull(); + } ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/jaxb/mapping/SimpleEntity.java b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/jaxb/mapping/SimpleEntity.java new file mode 100644 index 0000000000..5cdb1a02a6 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/jaxb/mapping/SimpleEntity.java @@ -0,0 +1,45 @@ +/* + * 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.boot.jaxb.mapping; + +import jakarta.persistence.Basic; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +/** + * @author Steve Ebersole + */ +@Entity +@Table( name = "simple_entity_table" ) +public class SimpleEntity { + @Id + private Integer id; + @Basic + private String name; + + private SimpleEntity() { + // for Hibernate use + } + + public SimpleEntity(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; + } +} \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/internal/util/xml/XMLMappingHelper.java b/hibernate-core/src/test/java/org/hibernate/orm/test/internal/util/xml/XMLMappingHelper.java index 51e8d73d00..f3ef8cdc8b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/internal/util/xml/XMLMappingHelper.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/internal/util/xml/XMLMappingHelper.java @@ -1,8 +1,8 @@ /* * 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 + * 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.internal.util.xml; @@ -12,7 +12,7 @@ import java.io.InputStream; import org.hibernate.boot.jaxb.Origin; import org.hibernate.boot.jaxb.SourceType; import org.hibernate.boot.jaxb.internal.MappingBinder; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; +import org.hibernate.boot.jaxb.mapping.JaxbEntityMappings; import org.hibernate.boot.jaxb.spi.Binding; import org.hibernate.testing.boot.ClassLoaderServiceTestingImpl; @@ -25,11 +25,11 @@ public final class XMLMappingHelper { private final MappingBinder binder; public XMLMappingHelper() { - binder = new MappingBinder( ClassLoaderServiceTestingImpl.INSTANCE, true ); + binder = new MappingBinder( ClassLoaderServiceTestingImpl.INSTANCE, MappingBinder.VALIDATING ); } public JaxbEntityMappings readOrmXmlMappings(String name) throws IOException { - try (InputStream is = ClassLoaderServiceTestingImpl.INSTANCE.locateResourceStream( name )) { + try ( InputStream is = ClassLoaderServiceTestingImpl.INSTANCE.locateResourceStream( name ) ) { return readOrmXmlMappings( is, name ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/JakartaXmlSmokeTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/JakartaXmlSmokeTests.java index d88329e2c1..b33c792a44 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/JakartaXmlSmokeTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/jakarta/JakartaXmlSmokeTests.java @@ -1,8 +1,8 @@ /* * 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 + * 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.jpa.jakarta; @@ -16,11 +16,11 @@ import javax.xml.transform.stream.StreamSource; import org.hibernate.boot.jaxb.Origin; import org.hibernate.boot.jaxb.SourceType; import org.hibernate.boot.jaxb.internal.MappingBinder; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEntity; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityListener; -import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; -import org.hibernate.boot.jaxb.mapping.spi.JaxbPersistenceUnitDefaults; -import org.hibernate.boot.jaxb.mapping.spi.JaxbPersistenceUnitMetadata; +import org.hibernate.boot.jaxb.mapping.JaxbEntity; +import org.hibernate.boot.jaxb.mapping.JaxbEntityListener; +import org.hibernate.boot.jaxb.mapping.JaxbEntityMappings; +import org.hibernate.boot.jaxb.mapping.JaxbPersistenceUnitDefaults; +import org.hibernate.boot.jaxb.mapping.JaxbPersistenceUnitMetadata; import org.hibernate.boot.jaxb.spi.Binding; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor; @@ -40,12 +40,15 @@ public class JakartaXmlSmokeTests { @Test public void testLoadingOrmXml(ServiceRegistryScope scope) { final ClassLoaderService cls = scope.getRegistry().getService( ClassLoaderService.class ); - final MappingBinder mappingBinder = new MappingBinder( cls, true ); + final MappingBinder mappingBinder = new MappingBinder( cls, MappingBinder.VALIDATING ); final InputStream inputStream = cls.locateResourceStream( "xml/jakarta/simple/orm.xml" ); try { final Binding binding = mappingBinder.bind( new StreamSource( inputStream ), new Origin( SourceType.RESOURCE, "xml/jakarta/simple/orm.xml" ) ); - assertThat( binding.getRoot().getEntity().stream().map( JaxbEntity::getClazz ) ).containsOnly( "Lighter", "ApplicationServer" ); + assertThat( binding.getRoot() + .getEntities() + .stream() + .map( JaxbEntity::getClazz ) ).containsOnly( "Lighter", "ApplicationServer" ); final JaxbPersistenceUnitMetadata puMetadata = binding.getRoot().getPersistenceUnitMetadata(); final JaxbPersistenceUnitDefaults puDefaults = puMetadata.getPersistenceUnitDefaults(); diff --git a/hibernate-core/src/test/resources/xml/jaxb/mapping/basic/hbm.xml b/hibernate-core/src/test/resources/xml/jaxb/mapping/basic/hbm.xml new file mode 100644 index 0000000000..95bf727bfe --- /dev/null +++ b/hibernate-core/src/test/resources/xml/jaxb/mapping/basic/hbm.xml @@ -0,0 +1,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/hibernate-core/src/test/resources/xml/jaxb/mapping/basic/orm.xml b/hibernate-core/src/test/resources/xml/jaxb/mapping/basic/orm.xml new file mode 100644 index 0000000000..a391d70a86 --- /dev/null +++ b/hibernate-core/src/test/resources/xml/jaxb/mapping/basic/orm.xml @@ -0,0 +1,17 @@ + + + + + org.hibernate.orm.test.boot.jaxb.mapping + + + + + + + \ No newline at end of file diff --git a/hibernate-core/src/test/resources/xml/jaxb/mapping/basic/unified.xml b/hibernate-core/src/test/resources/xml/jaxb/mapping/basic/unified.xml new file mode 100644 index 0000000000..4d0bb6eb26 --- /dev/null +++ b/hibernate-core/src/test/resources/xml/jaxb/mapping/basic/unified.xml @@ -0,0 +1,17 @@ + + + + + org.hibernate.orm.test.boot.jaxb.mapping + + + + + + + \ No newline at end of file diff --git a/hibernate-core/src/test/resources/xml/jaxb/mapping/partial/caching.xml b/hibernate-core/src/test/resources/xml/jaxb/mapping/partial/caching.xml new file mode 100644 index 0000000000..f5379ff802 --- /dev/null +++ b/hibernate-core/src/test/resources/xml/jaxb/mapping/partial/caching.xml @@ -0,0 +1,14 @@ + + + + + org.hibernate.orm.test.boot.jaxb.mapping + + + + \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index bd70737f3b..5d29a00ee6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -106,7 +106,7 @@ dependencyResolutionManagement { version( "jaxbRuntime", "3.0.2" ) version( "jsonbRuntime", "2.0.4" ) - // `jakartaJpaVersion` comes from the `` plugin - accounting for command-line overriding of the JPA version to use + // `jakartaJpaVersion` comes from the local-build-plugins to allow for command-line overriding of the JPA version to use alias( "jpa" ).to( "jakarta.persistence", "jakarta.persistence-api" ).version( "${jakartaJpaVersion}" ) alias( "jta" ).to( "jakarta.transaction", "jakarta.transaction-api" ).version( "2.0.0") alias( "validation" ).to( "jakarta.validation", "jakarta.validation-api" ).version( "3.0.0" ) diff --git a/tooling/hibernate-gradle-plugin/hibernate-gradle-plugin.gradle b/tooling/hibernate-gradle-plugin/hibernate-gradle-plugin.gradle index 77c8ef3e74..28788dc7e8 100644 --- a/tooling/hibernate-gradle-plugin/hibernate-gradle-plugin.gradle +++ b/tooling/hibernate-gradle-plugin/hibernate-gradle-plugin.gradle @@ -32,12 +32,15 @@ ext { } dependencies { - implementation project( ':hibernate-core' ) + implementation project(':hibernate-core') implementation libs.byteBuddy + implementation jakartaLibs.jaxbApi + implementation gradleApi() + implementation localGroovy() + // for Gradle implementation jakartaLibs.inject - implementation jakartaLibs.inject implementation localGroovy() } diff --git a/tooling/hibernate-gradle-plugin/src/main/java/org/hibernate/orm/tooling/gradle/misc/TransformHbmXmlTask.java b/tooling/hibernate-gradle-plugin/src/main/java/org/hibernate/orm/tooling/gradle/misc/TransformHbmXmlTask.java new file mode 100644 index 0000000000..2dddfdb9e1 --- /dev/null +++ b/tooling/hibernate-gradle-plugin/src/main/java/org/hibernate/orm/tooling/gradle/misc/TransformHbmXmlTask.java @@ -0,0 +1,240 @@ +/* + * 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.tooling.gradle.misc; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.Nested; +import org.gradle.api.tasks.OutputDirectory; +import org.gradle.api.tasks.SourceTask; +import org.gradle.api.tasks.TaskAction; + +import org.hibernate.boot.jaxb.Origin; +import org.hibernate.boot.jaxb.SourceType; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping; +import org.hibernate.boot.jaxb.hbm.transform.HbmXmlTransformer; +import org.hibernate.boot.jaxb.hbm.transform.UnsupportedFeatureHandling; +import org.hibernate.boot.jaxb.internal.MappingBinder; +import org.hibernate.boot.jaxb.mapping.JaxbEntityMappings; +import org.hibernate.boot.jaxb.spi.Binding; +import org.hibernate.boot.xsd.MappingXsdSupport; + +import jakarta.xml.bind.JAXBException; +import jakarta.xml.bind.Marshaller; + +/** + * Task to transform a legacy {@code `hbm.xml`} file into the + * {@link MappingXsdSupport#latestDescriptor() mapping} format. + *

+ * The task creates copies of {@code `hbm.xml`} files:

    + *
  • + * Into the specified {@link #getOutputDirectory() output directory}, + * if one was set; otherwise into the same directory as the + * {@code `hbm.xml`} file. + *
  • + *
  • + * Use {@link #getRenaming() renaming} to control the naming of the + * copies. + *
  • + *
+ * + * @author Steve Ebersole + * @apiNote See note on {@link TransformationNaming} with regard to + * making copies in place and not specifying renaming effectively + * replacing the original (destructive). + * @see org.hibernate.boot.jaxb.hbm.transform.HbmXmlTransformer + */ +public abstract class TransformHbmXmlTask extends SourceTask { + private final Property renaming; + private final Property unsupportedFeatures; + private final Property deleteHbmFiles; + + private final DirectoryProperty outputDirectory; + + public TransformHbmXmlTask() { + this.outputDirectory = getProject().getObjects().directoryProperty(); + + this.renaming = getProject().getObjects().property( TransformationNaming.class ); + this.renaming.set( new TransformationNaming( getProject().getObjects() ) ); + + this.unsupportedFeatures = getProject().getObjects().property( UnsupportedFeatureHandling.class ); + this.unsupportedFeatures.convention( UnsupportedFeatureHandling.ERROR ); + + this.deleteHbmFiles = getProject().getObjects().property( Boolean.class ); + this.deleteHbmFiles.convention( false ); + } + + /** + * Ability to create copies of the original with specific naming. + */ + @SuppressWarnings("unused") + @Nested + public Property getRenaming() { + return renaming; + } + + /** + * How should features supported in `hbm.xml` files, which are not supported for transformation, be handled? + */ + @Input + public Property getUnsupportedFeatures() { + return unsupportedFeatures; + } + + /** + * Should the {@code hbm.xml} files be deleted on successful transformation? + * Default is false. + */ + @Input + public Property getDeleteHbmFiles() { + return deleteHbmFiles; + } + + /** + * If set, transformed xml is written, relatively, to this directory. + *

+ * E.g. transforming the resource `org/hibernate/test/my_mappings.hbm.xml` + * into `/home/me/hibernate` would transform the HBM mapping and save it + * as `/home/me/hibernate/org/hibernate/test/my_mappings.hbm.xml` (depending + * on {@link #getRenaming() naming} any config + */ + @OutputDirectory + public DirectoryProperty getOutputDirectory() { + return outputDirectory; + } + + @TaskAction + public void transformFiles() { + final MappingBinder mappingBinder = new MappingBinder( + MappingBinder.class.getClassLoader()::getResourceAsStream, + unsupportedFeatures.getOrElse( UnsupportedFeatureHandling.ERROR ) + ); + + final Marshaller marshaller; + try { + marshaller = mappingBinder.mappingJaxbContext().createMarshaller(); + } + catch (JAXBException e) { + throw new RuntimeException( "Unable to create JAXB Marshaller", e ); + } + + getSource().forEach( (hbmXmlFile) -> transformFile( mappingBinder, marshaller, hbmXmlFile ) ); + } + + private void transformFile(MappingBinder mappingBinder, Marshaller marshaller, File hbmXmlFile) { + final Origin origin = new Origin( SourceType.FILE, hbmXmlFile.getAbsolutePath() ); + final Binding binding = bindMapping( mappingBinder, hbmXmlFile, origin ); + if ( binding == null ) { + return; + } + + if ( deleteHbmFiles.getOrElse( false ) ) { + final boolean deleted = hbmXmlFile.delete(); + if ( !deleted ) { + getProject().getLogger().warn( "Unable to delete hbm.xml file `{}`", hbmXmlFile.getAbsoluteFile() ); + } + } + + final HbmXmlTransformer.Options transformationOptions = unsupportedFeatures::get; + + final JaxbEntityMappings transformed = HbmXmlTransformer.transform( binding.getRoot(), origin, transformationOptions ); + + final String copyName = determineCopyName( hbmXmlFile ); + final File copyFile = determineCopyFile( copyName, hbmXmlFile ); + //noinspection ResultOfMethodCallIgnored + copyFile.getParentFile().mkdirs(); + try { + marshaller.marshal( transformed, copyFile ); + } + catch (JAXBException e) { + throw new RuntimeException( + "Unable to marshall mapping JAXB representation to file `" + copyFile.getAbsolutePath() + "`", + e + ); + } + } + + private Binding bindMapping(MappingBinder mappingBinder, File hbmXmlFile, Origin origin) { + try ( final FileInputStream fileStream = new FileInputStream( hbmXmlFile ) ) { + return mappingBinder.bind( fileStream, origin ); + } + catch (IOException e) { + getProject().getLogger() + .warn( "Unable to open hbm.xml file `" + hbmXmlFile.getAbsolutePath() + "` for transformation", e ); + return null; + } + } + + private File determineCopyFile(String copyName, File hbmXmlFile) { + if ( outputDirectory.isPresent() ) { + return outputDirectory.get().file( copyName ).getAsFile(); + } + else { + return new File( hbmXmlFile.getParentFile(), copyName ); + } + } + + private String determineCopyName(File hbmXmlFile) { + final String hbmXmlFileName = hbmXmlFile.getName(); + if ( !renaming.isPresent() ) { + return hbmXmlFileName; + } + + final TransformationNaming renaming = this.renaming.get(); + if ( renaming.areNoneDefined() ) { + return hbmXmlFileName; + } + + final String copyBaseName; + final String hbmXmlFileExtension; + final int legacyConventionExtensionIndex = hbmXmlFileName.indexOf( ".hbm.xml" ); + if ( legacyConventionExtensionIndex > 0 ) { + copyBaseName = hbmXmlFileName.substring( 0, legacyConventionExtensionIndex ); + hbmXmlFileExtension = ".hbm.xml"; + } + else { + final int extensionIndex = hbmXmlFileName.lastIndexOf( ".'" ); + if ( extensionIndex > 0 ) { + copyBaseName = hbmXmlFileName.substring( 0, legacyConventionExtensionIndex ); + hbmXmlFileExtension = hbmXmlFileName.substring( extensionIndex + 1 ); + } + else { + copyBaseName = hbmXmlFileName; + hbmXmlFileExtension = null; + } + } + + String copyName = copyBaseName; + + final String prefix = renaming.getPrefix().getOrNull(); + if ( prefix != null ) { + copyName = renaming.getPrefix().get() + copyName; + } + + final String suffix = renaming.getSuffix().getOrNull(); + if ( suffix != null ) { + copyName += suffix; + } + + final String extension = renaming.getExtension().getOrNull(); + if ( extension != null ) { + copyName += "."; + copyName += extension; + } + else if ( hbmXmlFileExtension != null ) { + copyName += "."; + copyName += hbmXmlFileExtension; + } + + return copyName; + } +} diff --git a/tooling/hibernate-gradle-plugin/src/main/java/org/hibernate/orm/tooling/gradle/misc/TransformationNaming.java b/tooling/hibernate-gradle-plugin/src/main/java/org/hibernate/orm/tooling/gradle/misc/TransformationNaming.java new file mode 100644 index 0000000000..a6a302d960 --- /dev/null +++ b/tooling/hibernate-gradle-plugin/src/main/java/org/hibernate/orm/tooling/gradle/misc/TransformationNaming.java @@ -0,0 +1,76 @@ +/* + * 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.tooling.gradle.misc; + +import java.io.Serializable; +import javax.inject.Inject; + +import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; + +/** + * Defines how we rename a file being transformed. + * + * @apiNote All settings set to null indicates to use the same file + * name. Note that with no {@link TransformHbmXmlTask#getOutputDirectory()} + * specified, this would mean replacing the original rather than making a + * copy (effectively, {@link TransformHbmXmlTask#getDeleteHbmFiles `deleteHbmFiles=true`}) + */ +public class TransformationNaming implements Serializable { + private final Property prefix; + private final Property suffix; + private final Property extension; + + @Inject + public TransformationNaming(ObjectFactory objectFactory) { + prefix = objectFactory.property( String.class ); + suffix = objectFactory.property( String.class ); + extension = objectFactory.property( String.class ); + } + + /** + * A prefix to apply to the file name. + *

+ * E.g. given an {@code `hbm.xml`} file named {@code `my-mappings.hbm.xml`} + * and a configured prefix of {@code `transformed-`}, the copy file's + * name would be {@code `transformed-my-mappings.hbm.xml`} + * + * @see #getExtension() + */ + @Input + public Property getPrefix() { + return prefix; + } + + /** + * A suffix to apply to the file name. + *

+ * E.g. given an {@code `hbm.xml`} file named {@code `my-mappings.hbm.xml`} + * and a configured suffix of {@code `-transformed`}, the copy file's + * name would be {@code `my-mappings-transformed.hbm.xml`} + * + * @see #getExtension() + */ + @Input + public Property getSuffix() { + return suffix; + } + + @Input + public Property getExtension() { + return extension; + } + + public boolean areAnyDefined() { + return prefix.isPresent() || suffix.isPresent() || extension.isPresent(); + } + + public boolean areNoneDefined() { + return !prefix.isPresent() && !suffix.isPresent() && !extension.isPresent(); + } +}