diff --git a/hibernate-models-orm/hibernate-models-orm.gradle b/hibernate-models-orm/hibernate-models-orm.gradle index bd8e509..2d84882 100644 --- a/hibernate-models-orm/hibernate-models-orm.gradle +++ b/hibernate-models-orm/hibernate-models-orm.gradle @@ -6,6 +6,7 @@ dependencies { implementation project( ":hibernate-models-common" ) implementation project( ":hibernate-models-source" ) + implementation project( ":hibernate-orm" ) implementation libs.hibernateCore implementation libs.jandex implementation libs.byteBuddy @@ -20,6 +21,6 @@ dependencies { testImplementation project( ":hibernate-models-testing" ) // testImplementation libs.hibernateTesting - testImplementation testLibs.jpa + testImplementation jakartaLibs.jpa testRuntimeOnly testLibs.log4j } diff --git a/hibernate-models-orm/src/main/java/org/hibernate/models/orm/HibernateAnnotations.java b/hibernate-models-orm/src/main/java/org/hibernate/models/orm/HibernateAnnotations.java index 446bc9d..5b6a739 100644 --- a/hibernate-models-orm/src/main/java/org/hibernate/models/orm/HibernateAnnotations.java +++ b/hibernate-models-orm/src/main/java/org/hibernate/models/orm/HibernateAnnotations.java @@ -10,7 +10,10 @@ import java.util.function.Consumer; import org.hibernate.annotations.*; -import org.hibernate.annotations.internal.Extends; +import org.hibernate.boot.internal.Abstract; +import org.hibernate.boot.internal.CollectionClassification; +import org.hibernate.boot.internal.Extends; +import org.hibernate.boot.internal.Target; import org.hibernate.models.orm.internal.OrmAnnotationHelper; import org.hibernate.models.source.spi.AnnotationDescriptor; @@ -68,7 +71,6 @@ public interface HibernateAnnotations { AnnotationDescriptor EMBEDDABLE_INSTANTIATOR = createOrmDescriptor( EmbeddableInstantiator.class ); AnnotationDescriptor EMBEDDABLE_INSTANTIATOR_REGS = createOrmDescriptor( EmbeddableInstantiatorRegistrations.class ); AnnotationDescriptor EMBEDDABLE_INSTANTIATOR_REG = createOrmDescriptor( EmbeddableInstantiatorRegistration.class, EMBEDDABLE_INSTANTIATOR_REGS ); - AnnotationDescriptor EXTENDS = createOrmDescriptor( Extends.class ); AnnotationDescriptor FETCH = createOrmDescriptor( Fetch.class ); AnnotationDescriptor FETCH_PROFILES = createOrmDescriptor( FetchProfiles.class ); AnnotationDescriptor FETCH_PROFILE = createOrmDescriptor( FetchProfile.class, FETCH_PROFILES ); @@ -156,7 +158,6 @@ public interface HibernateAnnotations { AnnotationDescriptor SYNCHRONIZE = createOrmDescriptor( Synchronize.class ); AnnotationDescriptor TABLES = createOrmDescriptor( Tables.class ); AnnotationDescriptor TABLE = createOrmDescriptor( Table.class, TABLES ); - AnnotationDescriptor TARGET = createOrmDescriptor( Target.class ); AnnotationDescriptor TENANT_ID = createOrmDescriptor( TenantId.class ); AnnotationDescriptor TZ_COLUMN = createOrmDescriptor( TimeZoneColumn.class ); AnnotationDescriptor TZ_STORAGE = createOrmDescriptor( TimeZoneStorage.class ); @@ -170,6 +171,10 @@ public interface HibernateAnnotations { AnnotationDescriptor WHERE = createOrmDescriptor( Where.class ); AnnotationDescriptor WHERE_JOIN_TABLE = createOrmDescriptor( WhereJoinTable.class ); + AnnotationDescriptor ABSTRACT = createOrmDescriptor( Abstract.class ); + AnnotationDescriptor COLLECTION_CLASSIFICATION = createOrmDescriptor( CollectionClassification.class ); + AnnotationDescriptor EXTENDS = createOrmDescriptor( Extends.class ); + AnnotationDescriptor TARGET = createOrmDescriptor( Target.class ); AnnotationDescriptor DIALECT_OVERRIDE_CHECKS = createOrmDescriptor( DialectOverride.Checks.class ); AnnotationDescriptor DIALECT_OVERRIDE_CHECK = createOrmDescriptor( DialectOverride.Check.class, DIALECT_OVERRIDE_CHECKS ); diff --git a/hibernate-models-orm/src/main/java/org/hibernate/models/orm/xml/internal/AttributeProcessor.java b/hibernate-models-orm/src/main/java/org/hibernate/models/orm/xml/internal/AttributeProcessor.java index bfa0406..7f98e9b 100644 --- a/hibernate-models-orm/src/main/java/org/hibernate/models/orm/xml/internal/AttributeProcessor.java +++ b/hibernate-models-orm/src/main/java/org/hibernate/models/orm/xml/internal/AttributeProcessor.java @@ -60,20 +60,6 @@ public static void processNaturalId( processBaseAttributes( jaxbNaturalId, mutableClassDetails, classAccessType, memberAdjuster, sourceModelBuildingContext ); } - public static void processBaseAttributes( - JaxbBaseAttributesContainer attributesContainer, - MutableClassDetails mutableClassDetails, - AccessType classAccessType, - SourceModelBuildingContext sourceModelBuildingContext) { - processBaseAttributes( - attributesContainer, - mutableClassDetails, - classAccessType, - null, - sourceModelBuildingContext - ); - } - public static void processBaseAttributes( JaxbBaseAttributesContainer attributesContainer, MutableClassDetails mutableClassDetails, diff --git a/hibernate-models-orm/src/main/java/org/hibernate/models/orm/xml/internal/ManagedTypeProcessor.java b/hibernate-models-orm/src/main/java/org/hibernate/models/orm/xml/internal/ManagedTypeProcessor.java index 39134cb..3a2e412 100644 --- a/hibernate-models-orm/src/main/java/org/hibernate/models/orm/xml/internal/ManagedTypeProcessor.java +++ b/hibernate-models-orm/src/main/java/org/hibernate/models/orm/xml/internal/ManagedTypeProcessor.java @@ -6,9 +6,14 @@ */ package org.hibernate.models.orm.xml.internal; +import java.util.Collection; import java.util.List; +import java.util.Map; +import java.util.Set; -import org.hibernate.annotations.internal.Extends; +import org.hibernate.boot.internal.Abstract; +import org.hibernate.boot.internal.Extends; +import org.hibernate.boot.internal.LimitedCollectionClassification; import org.hibernate.boot.jaxb.mapping.spi.JaxbAnyMappingImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbAttributesContainer; import org.hibernate.boot.jaxb.mapping.spi.JaxbAttributesContainerImpl; @@ -23,6 +28,7 @@ import org.hibernate.boot.jaxb.mapping.spi.JaxbMappedSuperclassImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbOneToOneImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbPersistentAttribute; +import org.hibernate.boot.jaxb.mapping.spi.JaxbPluralAttribute; import org.hibernate.models.ModelsException; import org.hibernate.models.internal.CollectionHelper; import org.hibernate.models.internal.StringHelper; @@ -301,6 +307,7 @@ private static void prepareDynamicClass( private static ClassDetails determineDynamicAttributeJavaType( JaxbPersistentAttribute jaxbPersistentAttribute, SourceModelBuildingContext sourceModelBuildingContext) { + final ClassDetailsRegistry classDetailsRegistry = sourceModelBuildingContext.getClassDetailsRegistry(); if ( jaxbPersistentAttribute instanceof JaxbIdImpl ) { final JaxbIdImpl jaxbId = (JaxbIdImpl) jaxbPersistentAttribute; @@ -309,11 +316,10 @@ private static ClassDetails determineDynamicAttributeJavaType( if ( jaxbPersistentAttribute instanceof JaxbEmbeddedIdImpl ) { final JaxbEmbeddedIdImpl jaxbEmbeddedId = (JaxbEmbeddedIdImpl) jaxbPersistentAttribute; - final String target = jaxbEmbeddedId.getEmbeddable(); + final String target = jaxbEmbeddedId.getTarget(); if ( StringHelper.isEmpty( target ) ) { return null; } - final ClassDetailsRegistry classDetailsRegistry = sourceModelBuildingContext.getClassDetailsRegistry(); return classDetailsRegistry.resolveClassDetails( target, () -> new DynamicClassDetails( target, sourceModelBuildingContext ) @@ -331,7 +337,6 @@ private static ClassDetails determineDynamicAttributeJavaType( if ( StringHelper.isEmpty( target ) ) { return null; } - final ClassDetailsRegistry classDetailsRegistry = sourceModelBuildingContext.getClassDetailsRegistry(); return classDetailsRegistry.resolveClassDetails( target, () -> new DynamicClassDetails( target, sourceModelBuildingContext ) @@ -344,7 +349,6 @@ private static ClassDetails determineDynamicAttributeJavaType( if ( StringHelper.isEmpty( target ) ) { return null; } - final ClassDetailsRegistry classDetailsRegistry = sourceModelBuildingContext.getClassDetailsRegistry(); return classDetailsRegistry.resolveClassDetails( target, () -> new DynamicClassDetails( @@ -358,9 +362,27 @@ private static ClassDetails determineDynamicAttributeJavaType( } if ( jaxbPersistentAttribute instanceof JaxbAnyMappingImpl ) { - return sourceModelBuildingContext.getClassDetailsRegistry().getClassDetails( Object.class.getName() ); + return classDetailsRegistry.getClassDetails( Object.class.getName() ); } + if ( jaxbPersistentAttribute instanceof JaxbPluralAttribute ) { + final JaxbPluralAttribute jaxbPluralAttribute = (JaxbPluralAttribute) jaxbPersistentAttribute; + final LimitedCollectionClassification classification = jaxbPluralAttribute.getClassification(); + switch ( classification ) { + case BAG: { + return classDetailsRegistry.resolveClassDetails( Collection.class.getName() ); + } + case LIST: { + return classDetailsRegistry.resolveClassDetails( List.class.getName() ); + } + case SET: { + return classDetailsRegistry.resolveClassDetails( Set.class.getName() ); + } + case MAP: { + return classDetailsRegistry.resolveClassDetails( Map.class.getName() ); + } + } + } throw new UnsupportedOperationException( "Resolution of dynamic attribute Java type not yet implemented for " + jaxbPersistentAttribute ); } @@ -375,23 +397,6 @@ private static void adjustDynamicTypeMember( ); } - private static void processNonDynamicEntity( - MutableClassDetails classDetails, - JaxbEntityImpl jaxbEntity, - AccessType classAccessType, - PersistenceUnitMetadata persistenceUnitMetadata, - SourceModelBuildingContext sourceModelBuildingContext) { - processEntityMetadata( - classDetails, - jaxbEntity, - classAccessType, - ManagedTypeProcessor::adjustNonDynamicTypeMember, - persistenceUnitMetadata, - sourceModelBuildingContext - ); - - } - private static void processEntityMetadata( MutableClassDetails classDetails, JaxbEntityImpl jaxbEntity, @@ -403,6 +408,10 @@ private static void processEntityMetadata( XmlAnnotationHelper.applyInheritance( jaxbEntity, classDetails, sourceModelBuildingContext ); classDetails.addAnnotationUsage( XmlAnnotationHelper.createAccessAnnotation( classAccessType, classDetails ) ); + if ( jaxbEntity.isAbstract() != null ) { + XmlProcessingHelper.makeAnnotation( Abstract.class, classDetails ); + } + if ( StringHelper.isNotEmpty( jaxbEntity.getExtends() ) ) { final DynamicAnnotationUsage extendsAnn = XmlProcessingHelper.makeAnnotation( Extends.class, @@ -456,129 +465,6 @@ private static void adjustNonDynamicTypeMember( ); } - private static void applyAttributesToDynamicClass( - MutableClassDetails dynamicClassDetails, - JaxbAttributesContainer attributes, - SourceModelBuildingContext sourceModelBuildingContext) { - attributes.getBasicAttributes().forEach( (jaxbBasic) -> { - final MapModeFieldDetails member = new MapModeFieldDetails( - jaxbBasic.getName(), - XmlAnnotationHelper.resolveJavaType( jaxbBasic.getType().getValue(), sourceModelBuildingContext ), - sourceModelBuildingContext - ); - dynamicClassDetails.addField( member ); - XmlAnnotationHelper.applyAttributeAccessor( - BuiltInPropertyAccessStrategies.MAP.getExternalName(), - member, - sourceModelBuildingContext - ); - } ); - attributes.getEmbeddedAttributes().forEach( (jaxbEmbedded) -> { - final MapModeFieldDetails member = new MapModeFieldDetails( - jaxbEmbedded.getName(), - null, - sourceModelBuildingContext - ); - dynamicClassDetails.addField( member ); - XmlAnnotationHelper.applyAttributeAccessor( - BuiltInPropertyAccessStrategies.MAP.getExternalName(), - member, - sourceModelBuildingContext - ); - } ); - attributes.getOneToOneAttributes().forEach( (jaxbOneToOne) -> { - final MapModeFieldDetails member = new MapModeFieldDetails( - jaxbOneToOne.getName(), - null, - sourceModelBuildingContext - ); - dynamicClassDetails.addField( member ); - XmlAnnotationHelper.applyAttributeAccessor( - BuiltInPropertyAccessStrategies.MAP.getExternalName(), - member, - sourceModelBuildingContext - ); - } ); - attributes.getManyToOneAttributes().forEach( (jaxbOneToOne) -> { - final MapModeFieldDetails member = new MapModeFieldDetails( - jaxbOneToOne.getName(), - null, - sourceModelBuildingContext - ); - dynamicClassDetails.addField( member ); - XmlAnnotationHelper.applyAttributeAccessor( - BuiltInPropertyAccessStrategies.MAP.getExternalName(), - member, - sourceModelBuildingContext - ); - } ); - attributes.getAnyMappingAttributes().forEach( (jaxbAny) -> { - final MapModeFieldDetails member = new MapModeFieldDetails( - jaxbAny.getName(), - null, - sourceModelBuildingContext - ); - dynamicClassDetails.addField( member ); - XmlAnnotationHelper.applyAttributeAccessor( - BuiltInPropertyAccessStrategies.MAP.getExternalName(), - member, - sourceModelBuildingContext - ); - } ); - attributes.getElementCollectionAttributes().forEach( (jaxbElementCollection) -> { - final MapModeFieldDetails member = new MapModeFieldDetails( - jaxbElementCollection.getName(), - null, - sourceModelBuildingContext - ); - dynamicClassDetails.addField( member ); - XmlAnnotationHelper.applyAttributeAccessor( - BuiltInPropertyAccessStrategies.MAP.getExternalName(), - member, - sourceModelBuildingContext - ); - } ); - attributes.getOneToManyAttributes().forEach( (jaxbOneToMany) -> { - final MapModeFieldDetails member = new MapModeFieldDetails( - jaxbOneToMany.getName(), - null, - sourceModelBuildingContext - ); - dynamicClassDetails.addField( member ); - XmlAnnotationHelper.applyAttributeAccessor( - BuiltInPropertyAccessStrategies.MAP.getExternalName(), - member, - sourceModelBuildingContext - ); - } ); - attributes.getManyToManyAttributes().forEach( (jaxbManyToMany) -> { - final MapModeFieldDetails member = new MapModeFieldDetails( - jaxbManyToMany.getName(), - null, - sourceModelBuildingContext - ); - dynamicClassDetails.addField( member ); - XmlAnnotationHelper.applyAttributeAccessor( - BuiltInPropertyAccessStrategies.MAP.getExternalName(), - member, - sourceModelBuildingContext - ); - } ); - attributes.getPluralAnyMappingAttributes().forEach( (jaxbManyToAny) -> { - final MapModeFieldDetails member = new MapModeFieldDetails( - jaxbManyToAny.getName(), - null, - sourceModelBuildingContext - ); - dynamicClassDetails.addField( member ); - XmlAnnotationHelper.applyAttributeAccessor( - BuiltInPropertyAccessStrategies.MAP.getExternalName(), - member, - sourceModelBuildingContext - ); - } ); - - } public static void processOverrideEntity( List> entityOverrides, PersistenceUnitMetadata persistenceUnitMetadata, @@ -717,14 +603,17 @@ public static void processCompleteEmbeddable( final AttributeProcessor.MemberAdjuster memberAdjuster; if ( StringHelper.isEmpty( jaxbEmbeddable.getClazz() ) ) { + if ( StringHelper.isEmpty( jaxbEmbeddable.getName() ) ) { + throw new ModelsException( "Embeddable did not define class nor name" ); + } // no class == dynamic... -// classDetails = (MutableClassDetails) sourceModelBuildingContext -// .getClassDetailsRegistry() -// .resolveClassDetails( jaxbEmbeddable.getName() ); -// classAccessType = AccessType.FIELD; -// memberAdjuster = ManagedTypeProcessor::adjustDynamicTypeMember; -// -// prepareDynamicClass( classDetails, jaxbEmbeddable, persistenceUnitMetadata, sourceModelBuildingContext ); + classDetails = (MutableClassDetails) sourceModelBuildingContext + .getClassDetailsRegistry() + .resolveClassDetails( jaxbEmbeddable.getName() ); + classAccessType = AccessType.FIELD; + memberAdjuster = ManagedTypeProcessor::adjustDynamicTypeMember; + + prepareDynamicClass( classDetails, jaxbEmbeddable, persistenceUnitMetadata, sourceModelBuildingContext ); throw new UnsupportedOperationException( "Not yet implemented" ); } diff --git a/hibernate-models-orm/src/main/java/org/hibernate/models/orm/xml/internal/XmlAnnotationHelper.java b/hibernate-models-orm/src/main/java/org/hibernate/models/orm/xml/internal/XmlAnnotationHelper.java index 79f6820..2b16dec 100644 --- a/hibernate-models-orm/src/main/java/org/hibernate/models/orm/xml/internal/XmlAnnotationHelper.java +++ b/hibernate-models-orm/src/main/java/org/hibernate/models/orm/xml/internal/XmlAnnotationHelper.java @@ -24,9 +24,9 @@ import org.hibernate.annotations.NaturalIdCache; import org.hibernate.annotations.OptimisticLock; import org.hibernate.annotations.Parameter; -import org.hibernate.annotations.Target; import org.hibernate.annotations.Type; import org.hibernate.annotations.UuidGenerator; +import org.hibernate.boot.internal.Target; import org.hibernate.boot.jaxb.mapping.spi.JaxbAssociationOverrideImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbAttributeOverrideImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbBasicImpl; diff --git a/hibernate-models-orm/src/test/java/org/hibernate/models/orm/xml/dynamic/DynamicModelTests.java b/hibernate-models-orm/src/test/java/org/hibernate/models/orm/xml/dynamic/DynamicModelTests.java index 59657e5..575bf08 100644 --- a/hibernate-models-orm/src/test/java/org/hibernate/models/orm/xml/dynamic/DynamicModelTests.java +++ b/hibernate-models-orm/src/test/java/org/hibernate/models/orm/xml/dynamic/DynamicModelTests.java @@ -6,7 +6,10 @@ */ package org.hibernate.models.orm.xml.dynamic; +import java.util.Set; + import org.hibernate.annotations.JavaType; +import org.hibernate.boot.internal.Target; import org.hibernate.models.orm.internal.ManagedResourcesImpl; import org.hibernate.models.orm.spi.EntityHierarchy; import org.hibernate.models.orm.spi.EntityTypeMetadata; @@ -74,4 +77,49 @@ public boolean shouldIgnoreUnlistedClasses() { assertThat( qtyField.getType().getClassName() ).isEqualTo( int.class.getName() ); } + @Test + void testSemiSimpleDynamicModel() { + final ManagedResources managedResources = new ManagedResourcesImpl.Builder() + .addXmlMappings( "mappings/dynamic/dynamic-semi-simple.xml" ) + .build(); + final Index jandexIndex = SourceModelTestHelper.buildJandexIndex( SIMPLE_CLASS_LOADING ); + final SourceModelBuildingContextImpl buildingContext = SourceModelTestHelper.createBuildingContext( + jandexIndex, + SIMPLE_CLASS_LOADING + ); + + final ProcessResult processResult = Processor.process( + managedResources, + null, + new Processor.Options() { + @Override + public boolean areGeneratorsGlobal() { + return false; + } + + @Override + public boolean shouldIgnoreUnlistedClasses() { + return false; + } + }, + buildingContext + ); + + assertThat( processResult.getEntityHierarchies() ).hasSize( 1 ); + final EntityHierarchy hierarchy = processResult.getEntityHierarchies().iterator().next(); + final EntityTypeMetadata rootEntity = hierarchy.getRoot(); + assertThat( rootEntity.getClassDetails().getClassName() ).isNull(); + assertThat( rootEntity.getClassDetails().getName() ).isEqualTo( "Contact" ); + + final FieldDetails idField = rootEntity.getClassDetails().findFieldByName( "id" ); + assertThat( idField.getType().getClassName() ).isEqualTo( Integer.class.getName() ); + + final FieldDetails nameField = rootEntity.getClassDetails().findFieldByName( "name" ); + assertThat( nameField.getType().getClassName() ).isEqualTo( "Name" ); + assertThat( nameField.getAnnotationUsage( Target.class ) ).isNotNull(); + + final FieldDetails labelsField = rootEntity.getClassDetails().findFieldByName( "labels" ); + assertThat( labelsField.getType().getClassName() ).isEqualTo( Set.class.getName() ); + } + } diff --git a/hibernate-models-orm/src/test/resources/mappings/dynamic/dynamic-semi-simple.xml b/hibernate-models-orm/src/test/resources/mappings/dynamic/dynamic-semi-simple.xml new file mode 100644 index 0000000..fd169b7 --- /dev/null +++ b/hibernate-models-orm/src/test/resources/mappings/dynamic/dynamic-semi-simple.xml @@ -0,0 +1,37 @@ + + + + + + Integer + BIGINT + + + Name + + + + + + + + + + + + + string + + + string + + + + \ No newline at end of file diff --git a/hibernate-models-source/hibernate-models-source.gradle b/hibernate-models-source/hibernate-models-source.gradle index 43e306e..d3b5ffa 100644 --- a/hibernate-models-source/hibernate-models-source.gradle +++ b/hibernate-models-source/hibernate-models-source.gradle @@ -4,7 +4,6 @@ dependencies { implementation project( ":hibernate-models-common" ) implementation libs.jandex - implementation libs.logging compileOnly libs.loggingAnnotations @@ -16,7 +15,6 @@ dependencies { testImplementation platform( libs.hibernatePlatform ) testImplementation project( ":hibernate-models-testing" ) testImplementation project( ":hibernate-models-orm" ) - testImplementation testLibs.jpa testImplementation libs.hibernateCore testRuntimeOnly testLibs.log4j diff --git a/hibernate-models-testing/hibernate-models-testing.gradle b/hibernate-models-testing/hibernate-models-testing.gradle index 1e3bf20..c06bcd2 100644 --- a/hibernate-models-testing/hibernate-models-testing.gradle +++ b/hibernate-models-testing/hibernate-models-testing.gradle @@ -7,7 +7,6 @@ dependencies { implementation libs.jandex testImplementation platform( libs.hibernatePlatform ) - testImplementation testLibs.jpa testImplementation libs.hibernateCore testRuntimeOnly testLibs.log4j } diff --git a/hibernate-orm/hibernate-orm.gradle b/hibernate-orm/hibernate-orm.gradle new file mode 100644 index 0000000..8acc074 --- /dev/null +++ b/hibernate-orm/hibernate-orm.gradle @@ -0,0 +1,42 @@ +plugins { + id "org.hibernate.build.xjc-jakarta" version "1.0.2" +} + +apply from: rootProject.file( "gradle/java-module.gradle" ) + +dependencies { + api platform( libs.hibernatePlatform ) + api libs.hibernateCore + + implementation jakartaLibs.jaxbApi + implementation jakartaLibs.jaxb + implementation jakartaLibs.inject + implementation libs.logging + + xjc jakartaLibs.xjc + xjc jakartaLibs.jaxb + xjc rootProject.fileTree(dir: 'patched-libs/jaxb2-basics', include: '*.jar') +} + +def jaxbTargetDir = project.file( "${buildDir}/generated/sources/xjc/main" ) + +xjc { + outputDirectory = jaxbTargetDir + + schemas { + mapping { + xsdFile = file( 'src/main/resources/org/hibernate/xsd/mapping/mapping-3.1.0.xsd' ) + xjcBindingFile = file( 'src/main/xjb/mapping-bindings.xjb' ) + xjcExtensions += ['inheritance', 'simplify'] + } + } +} + +sourceSets { + main { + // add the XJC generated JAXB classes to the main source-set + java{ + srcDir jaxbTargetDir + } + } +} \ No newline at end of file diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/internal/Abstract.java b/hibernate-orm/src/main/java/org/hibernate/boot/internal/Abstract.java new file mode 100644 index 0000000..8f38da8 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/internal/Abstract.java @@ -0,0 +1,22 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.boot.internal; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Used in mapping dynamic models to signify that an entity should be considered abstract. + * + * @author Steve Ebersole + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface Abstract { +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/internal/CollectionClassification.java b/hibernate-orm/src/main/java/org/hibernate/boot/internal/CollectionClassification.java new file mode 100644 index 0000000..18cdb83 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/internal/CollectionClassification.java @@ -0,0 +1,22 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.boot.internal; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Used in mapping dynamic models to signify the type of collection to use for a plural attribute + * + * @author Steve Ebersole + */ +@Target({ElementType.FIELD,ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface CollectionClassification { +} diff --git a/hibernate-models-orm/src/main/java/org/hibernate/annotations/internal/Extends.java b/hibernate-orm/src/main/java/org/hibernate/boot/internal/Extends.java similarity index 81% rename from hibernate-models-orm/src/main/java/org/hibernate/annotations/internal/Extends.java rename to hibernate-orm/src/main/java/org/hibernate/boot/internal/Extends.java index 82a96ee..e38e92c 100644 --- a/hibernate-models-orm/src/main/java/org/hibernate/annotations/internal/Extends.java +++ b/hibernate-orm/src/main/java/org/hibernate/boot/internal/Extends.java @@ -4,15 +4,15 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright: Red Hat Inc. and Hibernate Authors */ -package org.hibernate.annotations.internal; +package org.hibernate.boot.internal; import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import java.lang.annotation.Retention; /** - * Used to configure inheritance in dynamic models defined in XML + * Used in mapping dynamic models to specify from which other entity an entity extends. * * @author Steve Ebersole */ diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/internal/LimitedCollectionClassification.java b/hibernate-orm/src/main/java/org/hibernate/boot/internal/LimitedCollectionClassification.java new file mode 100644 index 0000000..af76ab1 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/internal/LimitedCollectionClassification.java @@ -0,0 +1,23 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.boot.internal; + +/** + * Limited set of {@linkplain org.hibernate.metamodel.CollectionClassification} + * used in mapping a dynamic model. + * + * @see org.hibernate.boot.jaxb.mapping.spi.JaxbCollectionClassificationImpl + * @see org.hibernate.metamodel.CollectionClassification + * + * @author Steve Ebersole + */ +public enum LimitedCollectionClassification { + BAG, + LIST, + SET, + MAP +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/internal/Target.java b/hibernate-orm/src/main/java/org/hibernate/boot/internal/Target.java new file mode 100644 index 0000000..9390fa7 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/internal/Target.java @@ -0,0 +1,40 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.boot.internal; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Used in mapping dynamic models to specify the java-type of an attribute, mainly for + * {@linkplain jakarta.persistence.Basic basic}, + * {@linkplain jakarta.persistence.Id id}, + * {@linkplain jakarta.persistence.Embedded embedded} and + * {@linkplain jakarta.persistence.EmbeddedId embedded-id} attributes. + * Can also be useful for {@linkplain org.hibernate.annotations.Any any} and + * {@linkplain org.hibernate.annotations.ManyToAny many-to-any} attributes to + * specify a base type. + *

+ * Other attribute classifications have spec-defined ways to specify the target

    + *
  • {@linkplain jakarta.persistence.ManyToOne#targetEntity()}
  • + *
  • {@linkplain jakarta.persistence.OneToOne#targetEntity()}
  • + *
  • {@linkplain jakarta.persistence.ElementCollection#targetClass()}
  • + *
  • {@linkplain jakarta.persistence.OneToMany#targetEntity()}
  • + *
  • {@linkplain jakarta.persistence.ManyToMany#targetEntity()}
  • + *
+ * + * @author Steve Ebersole + */ +@java.lang.annotation.Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Target { + /** + * The attribute's Java type + */ + Class targetClass(); +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/AbstractBinder.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/AbstractBinder.java new file mode 100644 index 0000000..5b158e2 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/AbstractBinder.java @@ -0,0 +1,179 @@ +/* + * 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; + +import java.io.InputStream; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; +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.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 { + private static final Logger log = Logger.getLogger( AbstractBinder.class ); + + private final LocalXmlResourceResolver xmlResourceResolver; + + protected AbstractBinder(ResourceStreamLocator resourceStreamLocator) { + this.xmlResourceResolver = new LocalXmlResourceResolver( resourceStreamLocator ); + } + + public abstract boolean isValidationEnabled(); + + @Override + public Binding bind(InputStream stream, Origin origin) { + final XMLEventReader eventReader = createReader( stream, origin ); + try { + return doBind( eventReader, origin ); + } + finally { + try { + eventReader.close(); + } + catch (XMLStreamException e) { + log.debug( "Unable to close StAX reader", e ); + } + } + } + + protected XMLEventReader createReader(InputStream stream, Origin origin) { + 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 MappingException( "Unable to create StAX reader", e, origin ); + } + } + + @Override + public Binding bind(Source source, Origin origin) { + final XMLEventReader eventReader = createReader( source, origin ); + return doBind( eventReader, origin ); + } + + protected XMLEventReader createReader(Source source, Origin origin) { + try { + // create a standard StAX reader + final XMLEventReader staxReader = staxFactory().createXMLEventReader( source ); + // and wrap it in a buffered reader (keeping 100 element sized buffer) + return new BufferedXMLEventReader( staxReader, 100 ); + } + catch ( XMLStreamException e ) { + throw new MappingException( "Unable to create StAX reader", e, origin ); + } + } + + private Binding doBind(XMLEventReader eventReader, Origin origin) { + try { + final StartElement rootElementStartEvent = seekRootElementStartEvent( eventReader, origin ); + return doBind( eventReader, rootElementStartEvent, origin ); + } + finally { + try { + eventReader.close(); + } + catch (Exception e) { + log.debug( "Unable to close StAX reader", e ); + + } + } + } + + private XMLInputFactory staxFactory; + + private XMLInputFactory staxFactory() { + if ( staxFactory == null ) { + staxFactory = buildStaxFactory(); + } + return staxFactory; + } + + private XMLInputFactory buildStaxFactory() { + XMLInputFactory staxFactory = XMLInputFactory.newInstance(); + staxFactory.setXMLResolver( xmlResourceResolver ); + return staxFactory; + } + + protected StartElement seekRootElementStartEvent(XMLEventReader staxEventReader, Origin origin) { + XMLEvent rootElementStartEvent; + try { + rootElementStartEvent = staxEventReader.peek(); + while ( rootElementStartEvent != null && !rootElementStartEvent.isStartElement() ) { + staxEventReader.nextEvent(); + rootElementStartEvent = staxEventReader.peek(); + } + } + catch ( Exception e ) { + throw new MappingException( "Error accessing StAX stream", e, origin ); + } + + if ( rootElementStartEvent == null ) { + throw new MappingException( "Could not locate root element", origin ); + } + + return rootElementStartEvent.asStartElement(); + } + + protected abstract Binding doBind(XMLEventReader staxEventReader, StartElement rootElementStartEvent, Origin origin); + + @SuppressWarnings("unused") + protected static boolean hasNamespace(StartElement startElement) { + return StringHelper.isNotEmpty( startElement.getName().getNamespaceURI() ); + } + + protected X jaxb(XMLEventReader reader, Schema xsd, JAXBContext jaxbContext, Origin origin) { + final ContextProvidingValidationEventHandler handler = new ContextProvidingValidationEventHandler(); + + try { + final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + if ( isValidationEnabled() ) { + unmarshaller.setSchema( xsd ); + } + else { + unmarshaller.setSchema( null ); + } + unmarshaller.setEventHandler( handler ); + + //noinspection unchecked + return (X) unmarshaller.unmarshal( reader ); + } + catch ( JAXBException e ) { + throw new MappingException( + "Unable to perform unmarshalling at line number " + handler.getLineNumber() + + " and column " + handler.getColumnNumber() + + ". Message: " + handler.getMessage(), + e, + origin + ); + } + } + + +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/CacheableFileXmlSource.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/CacheableFileXmlSource.java new file mode 100644 index 0000000..2f4aa74 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/CacheableFileXmlSource.java @@ -0,0 +1,152 @@ +/* + * 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.internal; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.Serializable; + +import org.hibernate.boot.MappingException; +import org.hibernate.boot.jaxb.Origin; +import org.hibernate.boot.jaxb.SourceType; +import org.hibernate.boot.jaxb.spi.Binder; +import org.hibernate.boot.jaxb.spi.Binding; +import org.hibernate.boot.jaxb.spi.XmlSource; +import org.hibernate.internal.CoreLogging; +import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.util.SerializationHelper; +import org.hibernate.type.SerializationException; + +/** + * @author Steve Ebersole + */ +public class CacheableFileXmlSource extends XmlSource { + private static final CoreMessageLogger log = CoreLogging.messageLogger( CacheableFileXmlSource.class ); + + private final File xmlFile; + private final File serFile; + private final boolean strict; + + public CacheableFileXmlSource(Origin origin, File xmlFile, File cachedFileDir, boolean strict) { + super( origin ); + this.xmlFile = xmlFile; + this.strict = strict; + + this.serFile = new File( cachedFileDir, xmlFile.getName() + ".bin" ); + + if ( strict ) { + if ( !serFile.exists() ) { + throw new MappingException( + String.format( "Cached file [%s] could not be found", origin.getName() ), + origin + ); + } + if ( isSerfileObsolete() ) { + throw new MappingException( + String.format( "Cached file [%s] could not be used as the mapping file is newer", origin.getName() ), + origin + ); + } + } + } + + public static File determineCachedFile(File xmlFile) { + return new File( xmlFile.getAbsolutePath() + ".bin" ); + } + + @Override + @SuppressWarnings("unchecked") + public Binding doBind(Binder binder) { + if ( strict ) { + try { + return new Binding( readSerFile(), getOrigin() ); + } + catch ( SerializationException e ) { + throw new MappingException( + String.format( "Unable to deserialize from cached file [%s]", getOrigin().getName() ) , + e, + getOrigin() + ); + } + catch ( FileNotFoundException e ) { + throw new MappingException( + String.format( "Unable to locate cached file [%s]", getOrigin().getName() ) , + e, + getOrigin() + ); + } + } + else { + if ( !isSerfileObsolete() ) { + try { + return readSerFile(); + } + catch ( SerializationException e ) { + log.unableToDeserializeCache( serFile.getName(), e ); + } + catch ( FileNotFoundException e ) { + log.cachedFileNotFound( serFile.getName(), e ); + } + } + else { + log.cachedFileObsolete( serFile ); + } + + log.readingMappingsFromFile( xmlFile.getPath() ); + final Binding binding = FileXmlSource.doBind( binder, xmlFile, getOrigin() ); + + writeSerFile( binding ); + + return binding; + } + } + + private T readSerFile() throws SerializationException, FileNotFoundException { + log.readingCachedMappings( serFile ); + return SerializationHelper.deserialize( new FileInputStream( serFile ) ); + } + + private void writeSerFile(Object binding) { + writeSerFile( (Serializable) binding, xmlFile, serFile ); + } + + private static void writeSerFile(Serializable binding, File xmlFile, File serFile) { + try ( FileOutputStream fos = new FileOutputStream( serFile ) ) { + if ( log.isDebugEnabled() ) { + log.debugf( "Writing cache file for: %s to: %s", xmlFile.getAbsolutePath(), serFile.getAbsolutePath() ); + } + SerializationHelper.serialize( binding, fos ); + boolean success = serFile.setLastModified( System.currentTimeMillis() ); + if ( !success ) { + log.warn( "Could not update cacheable hbm.xml bin file timestamp" ); + } + } + catch ( Exception e ) { + log.unableToWriteCachedFile( serFile.getAbsolutePath(), e.getMessage() ); + } + } + + public static void createSerFile(File xmlFile, Binder binder) { + createSerFile( xmlFile, determineCachedFile( xmlFile ), binder ); + } + + public static void createSerFile(File xmlFile, File outputFile, Binder binder) { + final Origin origin = new Origin( SourceType.FILE, xmlFile.getAbsolutePath() ); + writeSerFile( + FileXmlSource.doBind( binder, xmlFile, origin ), + xmlFile, + outputFile + ); + } + + private boolean isSerfileObsolete() { + return xmlFile.exists() && serFile.exists() && xmlFile.lastModified() > serFile.lastModified(); + } + +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/ContextProvidingValidationEventHandler.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/ContextProvidingValidationEventHandler.java new file mode 100644 index 0000000..c7b47db --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/ContextProvidingValidationEventHandler.java @@ -0,0 +1,43 @@ +/* + * 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; + +import jakarta.xml.bind.ValidationEvent; +import jakarta.xml.bind.ValidationEventHandler; +import jakarta.xml.bind.ValidationEventLocator; + +/** + * ValidationEventHandler implementation providing easier access to where (line/column) an error occurred. + * + * @author Steve Ebersole + */ +public class ContextProvidingValidationEventHandler implements ValidationEventHandler { + private int lineNumber; + private int columnNumber; + private String message; + + @Override + public boolean handleEvent(ValidationEvent validationEvent) { + ValidationEventLocator locator = validationEvent.getLocator(); + lineNumber = locator.getLineNumber(); + columnNumber = locator.getColumnNumber(); + message = validationEvent.getMessage(); + return false; + } + + public int getLineNumber() { + return lineNumber; + } + + public int getColumnNumber() { + return columnNumber; + } + + public String getMessage() { + return message; + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/FileXmlSource.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/FileXmlSource.java new file mode 100644 index 0000000..f4a0367 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/FileXmlSource.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 . + */ +package org.hibernate.boot.jaxb.internal; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; + +import org.hibernate.boot.MappingNotFoundException; +import org.hibernate.boot.jaxb.Origin; +import org.hibernate.boot.jaxb.spi.Binder; +import org.hibernate.boot.jaxb.spi.Binding; +import org.hibernate.boot.jaxb.spi.XmlSource; + +/** + * @author Steve Ebersole + */ +public class FileXmlSource extends XmlSource { + private final File file; + + public FileXmlSource(Origin origin, File file) { + super( origin ); + this.file = file; + } + + @Override + public Binding doBind(Binder binder) { + return doBind( binder, file, getOrigin() ); + } + + public static Binding doBind(Binder binder, File file, Origin origin) { + final FileInputStream fis; + try { + fis = new FileInputStream( file ); + } + catch ( FileNotFoundException e ) { + throw new MappingNotFoundException( e, origin ); + } + return InputStreamXmlSource.doBind( binder, fis, origin, true ); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/InputStreamAccessXmlSource.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/InputStreamAccessXmlSource.java new file mode 100644 index 0000000..933ebe4 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/InputStreamAccessXmlSource.java @@ -0,0 +1,36 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.boot.jaxb.internal; + +import org.hibernate.boot.archive.spi.InputStreamAccess; +import org.hibernate.boot.jaxb.Origin; +import org.hibernate.boot.jaxb.spi.Binder; +import org.hibernate.boot.jaxb.spi.Binding; +import org.hibernate.boot.jaxb.spi.XmlSource; + +/** + * @author Steve Ebersole + */ +public class InputStreamAccessXmlSource extends XmlSource { + private final InputStreamAccess inputStreamAccess; + + public InputStreamAccessXmlSource(Origin origin, InputStreamAccess inputStreamAccess) { + super( origin ); + this.inputStreamAccess = inputStreamAccess; + } + + @Override + public Binding doBind(Binder binder) { + return doBind( binder, inputStreamAccess, getOrigin() ); + } + + public static Binding doBind(Binder binder, InputStreamAccess inputStreamAccess, Origin origin) { + return inputStreamAccess.fromStream( + inputStream -> binder.bind( inputStream, origin ) + ); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/InputStreamXmlSource.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/InputStreamXmlSource.java new file mode 100644 index 0000000..2bca618 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/InputStreamXmlSource.java @@ -0,0 +1,59 @@ +/* + * 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.internal; + +import java.io.IOException; +import java.io.InputStream; + +import org.hibernate.boot.InvalidMappingException; +import org.hibernate.boot.jaxb.Origin; +import org.hibernate.boot.jaxb.spi.Binder; +import org.hibernate.boot.jaxb.spi.Binding; +import org.hibernate.boot.jaxb.spi.XmlSource; +import org.hibernate.internal.CoreLogging; + +import org.jboss.logging.Logger; + +/** + * @author Steve Ebersole + */ +public class InputStreamXmlSource extends XmlSource { + private static final Logger log = CoreLogging.logger( InputStreamXmlSource.class ); + + private final InputStream inputStream; + private final boolean autoClose; + + public InputStreamXmlSource(Origin origin, InputStream inputStream, boolean autoClose) { + super( origin ); + this.inputStream = inputStream; + this.autoClose = autoClose; + } + + @Override + public Binding doBind(Binder binder) { + return doBind( binder, inputStream, getOrigin(), autoClose ); + } + + public static Binding doBind(Binder binder, InputStream inputStream, Origin origin, boolean autoClose) { + try { + return binder.bind( inputStream, origin ); + } + catch ( Exception e ) { + throw new InvalidMappingException( origin, e ); + } + finally { + if ( autoClose ) { + try { + inputStream.close(); + } + catch ( IOException ignore ) { + log.trace( "Was unable to close input stream" ); + } + } + } + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/JarFileEntryXmlSource.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/JarFileEntryXmlSource.java new file mode 100644 index 0000000..80fe08b --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/JarFileEntryXmlSource.java @@ -0,0 +1,56 @@ +/* + * 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.internal; + +import java.io.IOException; +import java.io.InputStream; +import java.util.jar.JarFile; +import java.util.zip.ZipEntry; + +import org.hibernate.boot.MappingException; +import org.hibernate.boot.jaxb.Origin; +import org.hibernate.boot.jaxb.spi.Binder; +import org.hibernate.boot.jaxb.spi.Binding; +import org.hibernate.boot.jaxb.spi.XmlSource; + +/** + * @author Steve Ebersole + */ +public class JarFileEntryXmlSource extends XmlSource { + private final JarFile jarFile; + private final ZipEntry jarFileEntry; + + public JarFileEntryXmlSource( + Origin origin, + JarFile jarFile, + ZipEntry jarFileEntry) { + super( origin ); + this.jarFile = jarFile; + this.jarFileEntry = jarFileEntry; + } + + @Override + public Binding doBind(Binder binder) { + final InputStream stream; + try { + stream = jarFile.getInputStream( jarFileEntry ); + } + catch (IOException e) { + throw new MappingException( + String.format( + "Unable to open InputStream for jar file entry [%s : %s]", + jarFile.getName(), + jarFileEntry.getName() + ), + e, + getOrigin() + ); + } + + return InputStreamXmlSource.doBind( binder, stream, getOrigin(), true ); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/JaxpSourceXmlSource.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/JaxpSourceXmlSource.java new file mode 100644 index 0000000..2e8ad18 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/JaxpSourceXmlSource.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 . + */ +package org.hibernate.boot.jaxb.internal; + +import javax.xml.transform.Source; + +import org.hibernate.boot.jaxb.Origin; +import org.hibernate.boot.jaxb.spi.Binder; +import org.hibernate.boot.jaxb.spi.Binding; +import org.hibernate.boot.jaxb.spi.XmlSource; + +/** + * @author Steve Ebersole + */ +public class JaxpSourceXmlSource extends XmlSource { + private final Source jaxpSource; + + public JaxpSourceXmlSource(Origin origin, Source jaxpSource) { + super( origin ); + this.jaxpSource = jaxpSource; + } + + @Override + public Binding doBind(Binder binder) { + return binder.bind( jaxpSource, getOrigin() ); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java new file mode 100644 index 0000000..fa4dff1 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java @@ -0,0 +1,268 @@ +/* + * 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; + +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.internal.stax.MappingEventReader; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl; +import org.hibernate.boot.jaxb.spi.Binding; +import org.hibernate.boot.jaxb.spi.JaxbBindableMappingDescriptor; +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 { + 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 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 + public boolean isValidationEnabled() { + return optionsAccess.get().validateMappings(); + } + + @Override + protected Binding doBind( + XMLEventReader staxEventReader, + StartElement rootElementStartEvent, + Origin origin) { + final String rootElementLocalName = rootElementStartEvent.getName().getLocalPart(); + if ( "hibernate-mapping".equals( rootElementLocalName ) ) { + if ( log.isDebugEnabled() ) { + log.debugf( "Performing JAXB binding of hbm.xml document : %s", origin.toString() ); + } + + 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() ); + + final XMLEventReader reader = new MappingEventReader( staxEventReader, xmlEventFactory ); + final JaxbEntityMappingsImpl 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 ); + } + } + } + + private JAXBContext hbmJaxbContext() { + if ( hbmJaxbContext == null ) { + try { + hbmJaxbContext = JAXBContext.newInstance( JaxbHbmHibernateMapping.class ); + } + catch (JAXBException e) { + throw new ConfigurationException( "Unable to build hbm.xml JAXBContext", e ); + } + } + return hbmJaxbContext; + } + + @Internal + public JAXBContext mappingJaxbContext() { + if ( entityMappingsJaxbContext == null ) { + try { + entityMappingsJaxbContext = JAXBContext.newInstance( JaxbEntityMappingsImpl.class ); + } + catch (JAXBException e) { + throw new ConfigurationException( "Unable to build orm.xml JAXBContext", e ); + } + } + return entityMappingsJaxbContext; + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/UrlXmlSource.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/UrlXmlSource.java new file mode 100644 index 0000000..ea94b3a --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/UrlXmlSource.java @@ -0,0 +1,46 @@ +/* + * 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.internal; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.UnknownHostException; + +import org.hibernate.boot.MappingException; +import org.hibernate.boot.MappingNotFoundException; +import org.hibernate.boot.jaxb.Origin; +import org.hibernate.boot.jaxb.spi.Binder; +import org.hibernate.boot.jaxb.spi.Binding; +import org.hibernate.boot.jaxb.spi.XmlSource; + +/** + * @author Steve Ebersole + */ +public class UrlXmlSource extends XmlSource { + + private final URL url; + + public UrlXmlSource(Origin origin, URL url) { + super( origin ); + this.url = url; + } + + @Override + public Binding doBind(Binder binder) { + try { + InputStream stream = url.openStream(); + return InputStreamXmlSource.doBind( binder, stream, getOrigin(), true ); + } + catch (UnknownHostException e) { + throw new MappingNotFoundException( "Invalid URL", e, getOrigin() ); + } + catch (IOException e) { + throw new MappingException( "Unable to open URL InputStream", e, getOrigin() ); + } + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/XmlSources.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/XmlSources.java new file mode 100644 index 0000000..5506a58 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/XmlSources.java @@ -0,0 +1,148 @@ +/* + * 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; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Enumeration; +import java.util.function.Consumer; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import javax.xml.transform.dom.DOMSource; + +import org.hibernate.boot.MappingNotFoundException; +import org.hibernate.boot.archive.spi.InputStreamAccess; +import org.hibernate.boot.jaxb.JaxbLogger; +import org.hibernate.boot.jaxb.Origin; +import org.hibernate.boot.jaxb.SourceType; +import org.hibernate.boot.jaxb.spi.XmlSource; +import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; + +import org.w3c.dom.Document; + +/** + * Helper for building and handling {@link XmlSource} references. + *

+ * An {@code XmlSource} represents an XML document containing + * O/R mapping metadata, either a JPA {@code orm.xml} file, or a + * Hibernate {@code .hbm.xml} file. + * + * @author Steve Ebersole + */ +public class XmlSources { + /** + * Create an {@link XmlSource} from a named resource + */ + public static XmlSource fromResource(String resourceName, ClassLoaderService classLoaderService) { + JaxbLogger.JAXB_LOGGER.tracef( "reading mappings from resource : %s", resourceName ); + + final Origin origin = new Origin( SourceType.RESOURCE, resourceName ); + final URL url = classLoaderService.locateResource( resourceName ); + if ( url == null ) { + throw new MappingNotFoundException( origin ); + } + + return new UrlXmlSource( origin, url ); + } + + /** + * Create an {@link XmlSource} from a URL + */ + public static XmlSource fromUrl(URL url) { + final String urlExternalForm = url.toExternalForm(); + JaxbLogger.JAXB_LOGGER.tracef( "Reading mapping document from URL : %s", urlExternalForm ); + + final Origin origin = new Origin( SourceType.URL, urlExternalForm ); + return new UrlXmlSource( origin, url ); + } + + public static XmlSource fromFile(File file) { + final String filePath = file.getPath(); + JaxbLogger.JAXB_LOGGER.tracef( "reading mappings from file : %s", filePath ); + + final Origin origin = new Origin( SourceType.FILE, filePath ); + + if ( !file.exists() ) { + throw new MappingNotFoundException( origin ); + } + + return new FileXmlSource( origin, file ); + } + + public static XmlSource fromCacheableFile(File file) { + return fromCacheableFile( file, file.getParentFile() ); + } + + public static XmlSource fromCacheableFile(File file, File cacheableDir) { + return fromCacheableFile( file, cacheableDir, false ); + } + + public static XmlSource fromCacheableFile(File file, boolean strict) { + return fromCacheableFile( file, file.getParentFile(), strict ); + } + + public static XmlSource fromCacheableFile(File file, File cacheableDir, boolean strict) { + final String filePath = file.getPath(); + JaxbLogger.JAXB_LOGGER.tracef( "reading mappings from cacheable-file : %s", filePath ); + + final Origin origin = new Origin( SourceType.FILE, filePath ); + return new CacheableFileXmlSource( origin, file, cacheableDir, strict ); + } + + public static XmlSource fromStream(InputStreamAccess inputStreamAccess) { + final String streamName = inputStreamAccess.getStreamName(); + JaxbLogger.JAXB_LOGGER.tracef( "reading mappings from InputStreamAccess : %s", streamName ); + + final Origin origin = new Origin( SourceType.INPUT_STREAM, streamName ); + return new InputStreamAccessXmlSource( origin, inputStreamAccess ); + } + + public static XmlSource fromStream(InputStream inputStream) { + JaxbLogger.JAXB_LOGGER.trace( "reading mappings from InputStream" ); + + final Origin origin = new Origin( SourceType.INPUT_STREAM, null ); + return new InputStreamXmlSource( origin, inputStream, false ); + } + + public static XmlSource fromDocument(Document document) { + JaxbLogger.JAXB_LOGGER.trace( "reading mappings from DOM" ); + final Origin origin = new Origin( SourceType.DOM, Origin.UNKNOWN_FILE_PATH ); + return new JaxpSourceXmlSource( origin, new DOMSource( document ) ); + } + + /** + * Read all {@code .hbm.xml} mappings from a jar file and pass them + * to the given {@link Consumer}. + *

+ * Assumes that any file named {@code *.hbm.xml} is a mapping document. + * This method does not support {@code orm.xml} files! + * + * @param jar a jar file + * @param consumer a consumer of the resulting {@linkplain XmlSource XML sources} + */ + public static void fromJar(File jar, Consumer consumer) { + JaxbLogger.JAXB_LOGGER.tracef( "Seeking mapping documents in jar file : %s", jar.getName() ); + + final Origin origin = new Origin( SourceType.JAR, jar.getAbsolutePath() ); + + try ( JarFile jarFile = new JarFile(jar) ) { + final Enumeration entries = jarFile.entries(); + while ( entries.hasMoreElements() ) { + final JarEntry jarEntry = entries.nextElement(); + if ( jarEntry.getName().endsWith(".hbm.xml") ) { + JaxbLogger.JAXB_LOGGER.tracef( "Found hbm.xml mapping in jar : %s", jarEntry.getName() ); + consumer.accept( new JarFileEntryXmlSource( origin, jarFile, jarEntry ) ); + } + } + } + catch ( IOException e ) { + throw new MappingNotFoundException( e, origin ); + } + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/BaseXMLEventReader.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/BaseXMLEventReader.java new file mode 100644 index 0000000..a0ea008 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/BaseXMLEventReader.java @@ -0,0 +1,121 @@ +/* + * 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.internal.stax; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Characters; +import javax.xml.stream.events.EntityDeclaration; +import javax.xml.stream.events.EntityReference; +import javax.xml.stream.events.XMLEvent; +import javax.xml.stream.util.EventReaderDelegate; + +/** + * Base for XMLEventReader that implements the {@link #getElementText()} and {@link #nextTag()} APIs in a + * way that is agnostic from the rest of the XMLEventReader implementation. Both will use the subclasses + * {@link #internalNextEvent()} as the exclusive way to read events. + * + * Note, copied from the uPortal project by permission of author. See + * https://github.com/Jasig/uPortal/blob/master/uportal-war/src/main/java/org/jasig/portal/xml/stream/BaseXMLEventReader.java + * + * @author Eric Dalquist + */ +public abstract class BaseXMLEventReader extends EventReaderDelegate { + private XMLEvent previousEvent; + + public BaseXMLEventReader(XMLEventReader reader) { + super(reader); + } + + /** + * Subclass's version of {@link #nextEvent()}, called by {@link #next()} + */ + protected abstract XMLEvent internalNextEvent() throws XMLStreamException; + + /** + * @return The XMLEvent returned by the last call to {@link #internalNextEvent()} + */ + protected final XMLEvent getPreviousEvent() { + return this.previousEvent; + } + + @Override + public final XMLEvent nextEvent() throws XMLStreamException { + this.previousEvent = this.internalNextEvent(); + return this.previousEvent; + } + + @Override + public final Object next() { + try { + return this.nextEvent(); + } + catch (XMLStreamException e) { + return null; + } + } + + @Override + public final String getElementText() throws XMLStreamException { + XMLEvent event = this.previousEvent; + if (event == null) { + throw new XMLStreamException("Must be on START_ELEMENT to read next text, element was null"); + } + if (!event.isStartElement()) { + throw new XMLStreamException("Must be on START_ELEMENT to read next text", event.getLocation()); + } + + final StringBuilder text = new StringBuilder(); + while (!event.isEndDocument()) { + switch (event.getEventType()) { + case XMLStreamConstants.CHARACTERS: + case XMLStreamConstants.SPACE: + case XMLStreamConstants.CDATA: { + final Characters characters = event.asCharacters(); + text.append(characters.getData()); + break; + } + case XMLStreamConstants.ENTITY_REFERENCE: { + final EntityReference entityReference = (EntityReference)event; + final EntityDeclaration declaration = entityReference.getDeclaration(); + text.append(declaration.getReplacementText()); + break; + } + case XMLStreamConstants.COMMENT: + case XMLStreamConstants.PROCESSING_INSTRUCTION: { + //Ignore + break; + } + default: { + throw new XMLStreamException("Unexpected event type '" + XMLStreamConstantsUtils.getEventName(event.getEventType()) + "' encountered. Found event: " + event, event.getLocation()); + } + } + + event = this.nextEvent(); + } + + return text.toString(); + } + + @Override + public final XMLEvent nextTag() throws XMLStreamException { + XMLEvent event = this.nextEvent(); + while ((event.isCharacters() && event.asCharacters().isWhiteSpace()) + || event.isProcessingInstruction() + || event.getEventType() == XMLStreamConstants.COMMENT) { + + event = this.nextEvent(); + } + + if (!event.isStartElement() && event.isEndElement()) { + throw new XMLStreamException("Unexpected event type '" + XMLStreamConstantsUtils.getEventName(event.getEventType()) + "' encountered. Found event: " + event, event.getLocation()); + } + + return event; + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/BufferedXMLEventReader.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/BufferedXMLEventReader.java new file mode 100644 index 0000000..aaa38e9 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/BufferedXMLEventReader.java @@ -0,0 +1,175 @@ +/* + * 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.internal.stax; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.XMLEvent; + +/** + * Buffers XML events for later re-reading + * + * Note, copied from the uPortal project by permission of author. See + * https://github.com/Jasig/uPortal/blob/master/uportal-war/src/main/java/org/jasig/portal/xml/stream/BufferedXMLEventReader.java + * + * @author Eric Dalquist + */ +public class BufferedXMLEventReader extends BaseXMLEventReader { + private final LinkedList eventBuffer = new LinkedList<>(); + private int eventLimit; + private ListIterator bufferReader; + + /** + * Create new buffering reader, no buffering is done until {@link #mark(int)} is called. + */ + public BufferedXMLEventReader(XMLEventReader reader) { + super(reader); + } + + /** + * Create new buffering reader. Calls {@link #mark(int)} with the specified event limit + * @see #mark(int) + */ + public BufferedXMLEventReader(XMLEventReader reader, int eventLimit) { + super(reader); + this.eventLimit = eventLimit; + } + + /** + * @return A copy of the current buffer + */ + public List getBuffer() { + return new ArrayList<>(this.eventBuffer); + } + + @Override + protected XMLEvent internalNextEvent() throws XMLStreamException { + //If there is an iterator to read from reset was called, use the iterator + //until it runs out of events. + if (this.bufferReader != null) { + final XMLEvent event = this.bufferReader.next(); + + //If nothing left in the iterator, remove the reference and fall through to direct reading + if (!this.bufferReader.hasNext()) { + this.bufferReader = null; + } + + return event; + } + + //Get the next event from the underlying reader + final XMLEvent event = this.getParent().nextEvent(); + + //if buffering add the event + if (this.eventLimit != 0) { + this.eventBuffer.offer(event); + + //If limited buffer size and buffer is too big trim the buffer. + if (this.eventLimit > 0 && this.eventBuffer.size() > this.eventLimit) { + this.eventBuffer.poll(); + } + } + + return event; + } + + @Override + public boolean hasNext() { + return this.bufferReader != null || super.hasNext(); + } + + @Override + public XMLEvent peek() throws XMLStreamException { + if (this.bufferReader != null) { + final XMLEvent event = this.bufferReader.next(); + this.bufferReader.previous(); //move the iterator back + return event; + } + return super.peek(); + } + + /** + * Same as calling {@link #mark(int)} with -1. + */ + public void mark() { + this.mark(-1); + } + + /** + * Start buffering events + * @param eventLimit the maximum number of events to buffer. -1 will buffer all events, 0 will buffer no events. + */ + public void mark(int eventLimit) { + this.eventLimit = eventLimit; + + //Buffering no events now, clear the buffer and buffered reader + if (this.eventLimit == 0) { + this.eventBuffer.clear(); + this.bufferReader = null; + } + //Buffering limited set of events, lets trim the buffer if needed + else if (this.eventLimit > 0) { + //If there is an iterator check its current position and calculate the new iterator start position + int iteratorIndex = 0; + if (this.bufferReader != null) { + final int nextIndex = this.bufferReader.nextIndex(); + iteratorIndex = Math.max( 0, nextIndex - ( this.eventBuffer.size() - this.eventLimit ) ); + } + + //Trim the buffer until it is not larger than the limit + while (this.eventBuffer.size() > this.eventLimit) { + this.eventBuffer.poll(); + } + + //If there is an iterator re-create it using the newly calculated index + if (this.bufferReader != null) { + this.bufferReader = this.eventBuffer.listIterator(iteratorIndex); + } + } + } + + /** + * Reset the reader to these start of the buffered events. + */ + public void reset() { + if (this.eventBuffer.isEmpty()) { + this.bufferReader = null; + } + else { + this.bufferReader = this.eventBuffer.listIterator(); + } + } + + @Override + public void close() throws XMLStreamException { + this.mark(0); + super.close(); + } + + /** + * @return The number of events in the buffer. + */ + public int bufferSize() { + return this.eventBuffer.size(); + } + + /** + * If reading from the buffer after a {@link #reset()} call an {@link IllegalStateException} will be thrown. + */ + @Override + public void remove() { + if (this.bufferReader != null && this.bufferReader.hasNext()) { + throw new IllegalStateException("Cannot remove a buffered element"); + } + + super.remove(); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/FilteringXMLEventReader.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/FilteringXMLEventReader.java new file mode 100644 index 0000000..f202a79 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/FilteringXMLEventReader.java @@ -0,0 +1,123 @@ +/* + * 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.internal.stax; + +import java.util.Deque; +import java.util.LinkedList; +import java.util.NoSuchElementException; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; + +/** + * Base class for {@link XMLEventReader}s that want to modify or remove events from the reader stream. + * If a {@link StartElement} event is removed the subclass's {@link #filterEvent(XMLEvent, boolean)} will + * not see any events until after the matching {@link EndElement} event. + * + * Note, copied from the uPortal project by permission of author. See + * https://github.com/Jasig/uPortal/blob/master/uportal-war/src/main/java/org/jasig/portal/xml/stream/FilteringXMLEventReader.java + * + * @author Eric Dalquist + */ +public abstract class FilteringXMLEventReader extends BaseXMLEventReader { + private final Deque prunedElements = new LinkedList<>(); + private XMLEvent peekedEvent; + + public FilteringXMLEventReader(XMLEventReader reader) { + super(reader); + } + + @Override + protected final XMLEvent internalNextEvent() throws XMLStreamException { + return this.internalNext(false); + } + + @Override + public boolean hasNext() { + try { + return peekedEvent != null || (super.hasNext() && this.peek() != null); + } + catch (XMLStreamException e) { + throw new RuntimeException(e.getMessage(), e); + } + catch (NoSuchElementException e) { + return false; + } + } + + @Override + public final XMLEvent peek() throws XMLStreamException { + if (peekedEvent != null) { + return peekedEvent; + } + + peekedEvent = internalNext(true); + return peekedEvent; + } + + protected final XMLEvent internalNext(boolean peek) throws XMLStreamException { + XMLEvent event = null; + + if (peekedEvent != null) { + event = peekedEvent; + peekedEvent = null; + return event; + } + + do { + event = super.getParent().nextEvent(); + + //If there are pruned elements in the queue filtering events is still needed + if (!prunedElements.isEmpty()) { + //If another start element add it to the queue + if (event.isStartElement()) { + final StartElement startElement = event.asStartElement(); + prunedElements.push(startElement.getName()); + } + //If end element pop the newest name of the queue and double check that the start/end elements match up + else if (event.isEndElement()) { + final QName startElementName = prunedElements.pop(); + + final EndElement endElement = event.asEndElement(); + final QName endElementName = endElement.getName(); + + if (!startElementName.equals(endElementName)) { + throw new IllegalArgumentException("Malformed XMLEvent stream. Expected end element for " + startElementName + " but found end element for " + endElementName); + } + } + + event = null; + } + else { + final XMLEvent filteredEvent = this.filterEvent(event, peek); + + //If the event is being removed and it is a start element all elements until the matching + //end element need to be removed as well + if (filteredEvent == null && event.isStartElement()) { + final StartElement startElement = event.asStartElement(); + final QName name = startElement.getName(); + prunedElements.push(name); + } + + event = filteredEvent; + } + } + while (event == null); + + return event; + } + + /** + * @param event The current event + * @param peek If the event is from a {@link #peek()} call + * @return The event to return, if null is returned the event is dropped from the stream and the next event will be used. + */ + protected abstract XMLEvent filterEvent(XMLEvent event, boolean peek); +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/HbmEventReader.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/HbmEventReader.java new file mode 100644 index 0000000..bc6468c --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/HbmEventReader.java @@ -0,0 +1,96 @@ +/* + * 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.internal.stax; + +import java.util.ArrayList; +import java.util.Collections; +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.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; +import org.hibernate.internal.util.StringHelper; + +/** + * A StAX EventReader for {@code hbm.xml} files to add namespaces in documents + * not containing namespaces. + * + * @author Steve Ebersole + */ +public class HbmEventReader extends EventReaderDelegate { + + private static final List NAMESPACE_URIS_TO_MAP = Collections.singletonList( + // we need to recognize the initial, prematurely-chosen hbm.xml xsd namespace + "http://www.hibernate.org/xsd/hibernate-mapping" + ); + + private final XMLEventFactory xmlEventFactory; + + public HbmEventReader(XMLEventReader reader) { + this( reader, XMLEventFactory.newInstance() ); + } + + public HbmEventReader(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 && event.isStartElement() ) { + return applyNamespace( event.asStartElement() ); + } + return event; + } + + @SuppressWarnings("unchecked") + private StartElement applyNamespace(StartElement startElement) { + final List targetNamespaces = new ArrayList<>(); + + if ( StringHelper.isEmpty( startElement.getName().getNamespaceURI() ) ) { + // add the default namespace mapping + targetNamespaces.add( xmlEventFactory.createNamespace( MappingXsdSupport.INSTANCE.hbmXsd().getNamespaceUri() ) ); + } + + // transfer any namespaces directly, unless it is in the "to map" list in which case + // we transfer a mapped copy pointing to the new namespace + final Iterator originalNamespaces = startElement.getNamespaces(); + while ( originalNamespaces.hasNext() ) { + Namespace namespace = originalNamespaces.next(); + if ( NAMESPACE_URIS_TO_MAP.contains( namespace.getNamespaceURI() ) ) { + // this is a namespace "to map" so map it + namespace = xmlEventFactory.createNamespace( namespace.getPrefix(), MappingXsdSupport.INSTANCE.hbmXsd().getNamespaceUri() ); + } + targetNamespaces.add( namespace ); + } + + // 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.INSTANCE.hbmXsd().getNamespaceUri(), startElement.getName().getLocalPart() ), + startElement.getAttributes(), + targetNamespaces.iterator() + ); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/JpaOrmXmlEventReader.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/JpaOrmXmlEventReader.java new file mode 100644 index 0000000..4784f6f --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/JpaOrmXmlEventReader.java @@ -0,0 +1,198 @@ +/* + * 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.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 which handles a few oddities specific to JPA {@code orm.xml} + * + * Mainly we handle the namespace change. + * + * Ultimately we should handle "upgrading" the documents as well. The idea being that + * we'd always treat all versions as the latest. + * + * {@see HHH-8108} for more discussion. + * + * @author Strong Liu + * @author Steve Ebersole + * @author Hardy Ferentschik + */ +public class JpaOrmXmlEventReader extends EventReaderDelegate { + + private static final String ROOT_ELEMENT_NAME = "entity-mappings"; + private static final String VERSION_ATTRIBUTE_NAME = "version"; + + private final XMLEventFactory xmlEventFactory; + + public JpaOrmXmlEventReader(XMLEventReader reader) { + this( reader, XMLEventFactory.newInstance() ); + } + + public JpaOrmXmlEventReader(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.INSTANCE.latestJpaDescriptor().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; + } + + @SuppressWarnings("unchecked") + 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.latestJpaDescriptor().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.INSTANCE.latestJpaDescriptor().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.INSTANCE.latestJpaDescriptor().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.INSTANCE.latestJpaDescriptor().getNamespaceUri(), endElement.getName().getLocalPart() ), + targetNamespaces.iterator() + ); + } + + @SuppressWarnings("unchecked") + 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-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/LocalSchemaLocator.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/LocalSchemaLocator.java new file mode 100644 index 0000000..0332bb9 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/LocalSchemaLocator.java @@ -0,0 +1,75 @@ +/* + * 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.internal.stax; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import javax.xml.XMLConstants; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; + +import org.jboss.logging.Logger; + +/** + * Helper for resolving XML Schema references locally. + * + * @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 ); + + private LocalSchemaLocator() { + // Disallow direct instantiation + } + + /** + * Given the resource name of a schema, locate its URL reference via ClassLoader lookup. + * + * @param schemaResourceName The local resource name to the schema + * + */ + public static URL resolveLocalSchemaUrl(String schemaResourceName) { + URL url = LocalSchemaLocator.class.getClassLoader().getResource( schemaResourceName ); + if ( url == null ) { + throw new XmlInfrastructureException( "Unable to locate schema [" + schemaResourceName + "] via classpath" ); + } + return url; + } + + public static Schema resolveLocalSchema(String schemaName){ + return resolveLocalSchema( resolveLocalSchemaUrl( schemaName ) ); + } + + public static Schema resolveLocalSchema(URL schemaUrl) { + try { + InputStream schemaStream = schemaUrl.openStream(); + try { + StreamSource source = new StreamSource(schemaUrl.openStream()); + SchemaFactory schemaFactory = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI ); + return schemaFactory.newSchema(source); + } + catch ( Exception e ) { + throw new XmlInfrastructureException( "Unable to load schema [" + schemaUrl.toExternalForm() + "]", e ); + } + finally { + try { + schemaStream.close(); + } + catch ( IOException e ) { + log.debugf( "Problem closing schema stream - %s", e.toString() ); + } + } + } + catch ( IOException e ) { + throw new XmlInfrastructureException( "Stream error handling schema url [" + schemaUrl.toExternalForm() + "]" ); + } + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/LocalXmlResourceResolver.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/LocalXmlResourceResolver.java new file mode 100644 index 0000000..7f46731 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/LocalXmlResourceResolver.java @@ -0,0 +1,225 @@ +/* + * 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.io.IOException; +import java.io.InputStream; +import java.net.URL; +import javax.xml.stream.XMLStreamException; + +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; + +import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER; + +/** + * @author Steve Ebersole + */ +public class LocalXmlResourceResolver implements javax.xml.stream.XMLResolver { + private static final Logger log = Logger.getLogger( LocalXmlResourceResolver.class ); + + public static final String CLASSPATH_EXTENSION_URL_BASE = "classpath://"; + + private final ResourceStreamLocator resourceStreamLocator; + + public LocalXmlResourceResolver(ResourceStreamLocator resourceStreamLocator) { + this.resourceStreamLocator = resourceStreamLocator; + } + + @Override + public Object resolveEntity(String publicID, String systemID, String baseURI, String namespace) throws XMLStreamException { + log.tracef( "In resolveEntity(%s, %s, %s, %s)", publicID, systemID, baseURI, namespace ); + + 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( MappingXsdSupport.jpa10 ); + } + else if ( MappingXsdSupport.jpa21.getNamespaceUri().matches( namespace ) ) { + // JPA 2.1 and 2.2 share the same namespace URI + return openUrlStream( MappingXsdSupport.jpa21 ); + } + else if ( MappingXsdSupport.jpa30.getNamespaceUri().matches( namespace ) ) { + return openUrlStream( MappingXsdSupport.jpa30 ); + } + else if ( MappingXsdSupport.jpa31.getNamespaceUri().matches( namespace ) ) { + return openUrlStream( MappingXsdSupport.jpa31 ); + } + else if ( ConfigXsdSupport.getJPA10().getNamespaceUri().matches( namespace ) ) { + // JPA 1.0 and 2.0 share the same namespace URI + return openUrlStream( ConfigXsdSupport.getJPA10() ); + } + else if ( ConfigXsdSupport.getJPA21().getNamespaceUri().matches( namespace ) ) { + // JPA 2.1 and 2.2 share the same namespace URI + return openUrlStream( ConfigXsdSupport.getJPA21() ); + } + else if ( ConfigXsdSupport.getJPA30().getNamespaceUri().matches( namespace ) ) { + return openUrlStream( ConfigXsdSupport.getJPA30() ); + } + else if ( ConfigXsdSupport.getJPA31().getNamespaceUri().matches( namespace ) ) { + return openUrlStream( ConfigXsdSupport.getJPA31() ); + } + else if ( MappingXsdSupport.hibernateMappingXml.getNamespaceUri().matches( namespace ) ) { + return openUrlStream( MappingXsdSupport.hibernateMappingXml ); + } + else if ( MappingXsdSupport.hbmXml.getNamespaceUri().matches( namespace ) ) { + return openUrlStream( MappingXsdSupport.hbmXml ); + } + else if ( ConfigXsdSupport.cfgXsd().getNamespaceUri().matches( namespace ) ) { + return openUrlStream( ConfigXsdSupport.cfgXsd() ); + } + } + + if ( publicID != null || systemID != null ) { + log.debugf( "Checking public/system identifiers `%s`/`%s` as DTD references", publicID, systemID ); + + if ( MAPPING_DTD.matches( publicID, systemID ) ) { + return openUrlStream( MAPPING_DTD.localSchemaUrl ); + } + + if ( ALTERNATE_MAPPING_DTD.matches( publicID, systemID ) ) { + return openUrlStream( ALTERNATE_MAPPING_DTD.localSchemaUrl ); + } + + if ( LEGACY_MAPPING_DTD.matches( publicID, systemID ) ) { + DEPRECATION_LOGGER.recognizedObsoleteHibernateNamespace( LEGACY_MAPPING_DTD.getIdentifierBase(), MAPPING_DTD.getIdentifierBase() ); + return openUrlStream( MAPPING_DTD.localSchemaUrl ); + } + + if ( CFG_DTD.matches( publicID, systemID ) ) { + return openUrlStream( CFG_DTD.localSchemaUrl ); + } + + if ( ALTERNATE_CFG_DTD.matches( publicID, systemID ) ) { + return openUrlStream( ALTERNATE_CFG_DTD.localSchemaUrl ); + } + + if ( LEGACY_CFG_DTD.matches( publicID, systemID ) ) { + DEPRECATION_LOGGER.recognizedObsoleteHibernateNamespace( LEGACY_CFG_DTD.getIdentifierBase(), CFG_DTD.getIdentifierBase() ); + return openUrlStream( CFG_DTD.localSchemaUrl ); + } + } + + if ( systemID != null ) { + // technically, "classpath://..." identifiers should only be declared as SYSTEM identifiers + if ( systemID.startsWith( CLASSPATH_EXTENSION_URL_BASE ) ) { + log.debugf( "Recognized `classpath:` identifier; attempting to resolve on classpath [%s]", systemID ); + final String path = systemID.substring( CLASSPATH_EXTENSION_URL_BASE.length() ); + // todo : for this to truly work consistently, we need access to ClassLoaderService + final InputStream stream = resolveInLocalNamespace( path ); + if ( stream == null ) { + log.debugf( "Unable to resolve [%s] on classpath", systemID ); + } + else { + log.debugf( "Resolved [%s] on classpath", systemID ); + } + return stream; + } + } + + return null; + } + + private InputStream openUrlStream(XsdDescriptor xsdDescriptor) { + return openUrlStream( LocalSchemaLocator.resolveLocalSchemaUrl( xsdDescriptor.getLocalResourceName() ) ); + } + + private InputStream openUrlStream(URL url) { + try { + return url.openStream(); + } + catch (IOException e) { + throw new XmlInfrastructureException( "Could not open url stream : " + url.toExternalForm(), e ); + } + } + + private InputStream resolveInLocalNamespace(String path) { + try { + return resourceStreamLocator.locateResourceStream( path ); + } + catch ( Throwable t ) { + return null; + } + } + + public static final DtdDescriptor MAPPING_DTD = new DtdDescriptor( + "www.hibernate.org/dtd/hibernate-mapping", + "org/hibernate/hibernate-mapping-3.0.dtd" + ); + + public static final DtdDescriptor ALTERNATE_MAPPING_DTD = new DtdDescriptor( + "hibernate.org/dtd/hibernate-mapping", + "org/hibernate/hibernate-mapping-3.0.dtd" + ); + + public static final DtdDescriptor LEGACY_MAPPING_DTD = new DtdDescriptor( + "hibernate.sourceforge.net/hibernate-mapping", + "org/hibernate/hibernate-mapping-3.0.dtd" + ); + + public static final DtdDescriptor CFG_DTD = new DtdDescriptor( + "www.hibernate.org/dtd/hibernate-configuration", + "org/hibernate/hibernate-configuration-3.0.dtd" + ); + + public static final DtdDescriptor ALTERNATE_CFG_DTD = new DtdDescriptor( + "hibernate.org/dtd/hibernate-configuration", + "org/hibernate/hibernate-configuration-3.0.dtd" + ); + + public static final DtdDescriptor LEGACY_CFG_DTD = new DtdDescriptor( + "hibernate.sourceforge.net/hibernate-configuration", + "org/hibernate/hibernate-configuration-3.0.dtd" + ); + + + public static class DtdDescriptor { + private final String httpBase; + private final String httpsBase; + private final URL localSchemaUrl; + + public DtdDescriptor(String identifierBase, String resourceName) { + this.httpBase = "http://" + identifierBase; + this.httpsBase = "https://" + identifierBase; + this.localSchemaUrl = LocalSchemaLocator.resolveLocalSchemaUrl( resourceName ); + } + + public String getIdentifierBase() { + return httpBase; + } + + public boolean matches(String publicId, String systemId) { + if ( publicId != null ) { + if ( publicId.startsWith( httpBase ) + || publicId.startsWith( httpsBase ) ) { + return true; + } + } + + if ( systemId != null ) { + if ( systemId.startsWith( httpBase ) + || systemId.startsWith( httpsBase ) ) { + return true; + } + } + + return false; + } + + public URL getMappedLocalUrl() { + return localSchemaUrl; + } + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/MappingEventReader.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/MappingEventReader.java new file mode 100644 index 0000000..8545eb3 --- /dev/null +++ b/hibernate-orm/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-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/XMLStreamConstantsUtils.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/XMLStreamConstantsUtils.java new file mode 100644 index 0000000..53e8737 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/XMLStreamConstantsUtils.java @@ -0,0 +1,51 @@ +/* + * 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.internal.stax; + +import javax.xml.stream.XMLStreamConstants; + +/** + * Note, copied from the uPortal project by permission of author. See + * https://github.com/Jasig/uPortal/blob/master/uportal-war/src/main/java/org/jasig/portal/xml/stream/XMLStreamConstantsUtils.java + * + * @author Eric Dalquist + */ +public final class XMLStreamConstantsUtils { + private XMLStreamConstantsUtils() { + } + + /** + * Get the human readable event name for the numeric event id + */ + public static String getEventName(int eventId) { + switch (eventId) { + case XMLStreamConstants.START_ELEMENT: + return "StartElementEvent"; + case XMLStreamConstants.END_ELEMENT: + return "EndElementEvent"; + case XMLStreamConstants.PROCESSING_INSTRUCTION: + return "ProcessingInstructionEvent"; + case XMLStreamConstants.CHARACTERS: + return "CharacterEvent"; + case XMLStreamConstants.COMMENT: + return "CommentEvent"; + case XMLStreamConstants.START_DOCUMENT: + return "StartDocumentEvent"; + case XMLStreamConstants.END_DOCUMENT: + return "EndDocumentEvent"; + case XMLStreamConstants.ENTITY_REFERENCE: + return "EntityReferenceEvent"; + case XMLStreamConstants.ATTRIBUTE: + return "AttributeBase"; + case XMLStreamConstants.DTD: + return "DTDEvent"; + case XMLStreamConstants.CDATA: + return "CDATA"; + } + return "UNKNOWN_EVENT_TYPE"; + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/XmlInfrastructureException.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/XmlInfrastructureException.java new file mode 100644 index 0000000..1a4e6c4 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/XmlInfrastructureException.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 . + */ +package org.hibernate.boot.jaxb.internal.stax; + +import org.hibernate.HibernateException; + +/** + * An error using XML infrastructure (jaxp, stax, etc). + * + * @author Steve Ebersole + */ +public class XmlInfrastructureException extends HibernateException { + public XmlInfrastructureException(String message) { + super( message ); + } + + public XmlInfrastructureException(String message, Throwable root) { + super( message, root ); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/package-info.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/package-info.java new file mode 100644 index 0000000..99caa21 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/internal/stax/package-info.java @@ -0,0 +1,11 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +/** + * Contains basic support for Java XML Processing (JAXP) via Streaming API for XML (StAX) + */ +package org.hibernate.boot.jaxb.internal.stax; diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/AccessTypeMarshalling.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/AccessTypeMarshalling.java new file mode 100644 index 0000000..2f11f1a --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/AccessTypeMarshalling.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.internal; + +import jakarta.persistence.AccessType; + +/** + * JAXB marshalling for JPA's {@link AccessType} + * + * @author Steve Ebersole + */ +public class AccessTypeMarshalling { + public static AccessType fromXml(String name) { + return name == null ? null : AccessType.valueOf( name ); + } + + public static String toXml(AccessType accessType) { + return accessType == null ? null : accessType.name(); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/CacheAccessTypeMarshalling.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/CacheAccessTypeMarshalling.java new file mode 100644 index 0000000..631d472 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/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.internal; + +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 name == null ? null : AccessType.fromExternalName( name ); + } + + public static String toXml(AccessType accessType) { + return accessType == null ? null : accessType.name(); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/CacheModeMarshalling.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/CacheModeMarshalling.java new file mode 100644 index 0000000..0919789 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/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.internal; + +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 == null ? null : cacheMode.name().toLowerCase( Locale.ENGLISH ); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/CollectionClassificationMarshalling.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/CollectionClassificationMarshalling.java new file mode 100644 index 0000000..9e960ea --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/CollectionClassificationMarshalling.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.internal; + +import org.hibernate.metamodel.CollectionClassification; + +/** + * JAXB marshalling for {@link CollectionClassification} + * + * @author Steve Ebersole + */ +public class CollectionClassificationMarshalling { + public static CollectionClassification fromXml(String name) { + return name == null ? null : CollectionClassification.interpretSetting( name.replace( '-', '_' ) ); + } + + public static String toXml(CollectionClassification classification) { + return classification == null ? null : classification.name().replace( '_', '-' ); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/ConstraintModeMarshalling.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/ConstraintModeMarshalling.java new file mode 100644 index 0000000..670a1b6 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/ConstraintModeMarshalling.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.internal; + +import jakarta.persistence.ConstraintMode; + +/** + * JAXB marshalling for JPA's {@link ConstraintMode} + * + * @author Steve Ebersole + */ +public class ConstraintModeMarshalling { + public static ConstraintMode fromXml(String name) { + return name == null ? null : ConstraintMode.valueOf( name ); + } + + public static String toXml(ConstraintMode constraintMode) { + return constraintMode == null ? null : constraintMode.name(); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/DiscriminatorTypeMarshalling.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/DiscriminatorTypeMarshalling.java new file mode 100644 index 0000000..15a9041 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/DiscriminatorTypeMarshalling.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.internal; + +import jakarta.persistence.DiscriminatorType; + +/** + * JAXB marshalling for {@link DiscriminatorType} + * + * @author Steve Ebersole + */ +public class DiscriminatorTypeMarshalling { + public static DiscriminatorType fromXml(String name) { + return name == null ? null : DiscriminatorType.valueOf( name ); + } + + public static String toXml(DiscriminatorType discriminatorType) { + return discriminatorType == null ? null : discriminatorType.name(); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/EnumTypeMarshalling.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/EnumTypeMarshalling.java new file mode 100644 index 0000000..84322b8 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/EnumTypeMarshalling.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.internal; + +import jakarta.persistence.EnumType; + +/** + * JAXB marshalling for {@link EnumType} + * + * @author Steve Ebersole + */ +public class EnumTypeMarshalling { + public static EnumType fromXml(String name) { + return name == null ? null : EnumType.valueOf( name ); + } + + public static String toXml(EnumType enumType) { + return enumType == null ? null : enumType.name(); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/FetchTypeMarshalling.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/FetchTypeMarshalling.java new file mode 100644 index 0000000..7c8c458 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/FetchTypeMarshalling.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.internal; + +import jakarta.persistence.FetchType; + +/** + * JAXB marshalling for {@link FetchType} + * + * @author Steve Ebersole + */ +public class FetchTypeMarshalling { + public static FetchType fromXml(String name) { + return name == null ? null : FetchType.valueOf( name ); + } + + public static String toXml(FetchType fetchType) { + return fetchType == null ? null : fetchType.name(); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/FlushModeMarshalling.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/FlushModeMarshalling.java new file mode 100644 index 0000000..8fb41c1 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/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.internal; + +import java.util.Locale; + +import org.hibernate.FlushMode; +import org.hibernate.HibernateException; + +/** + * JAXB marshalling for {@link FlushMode} + * + * @implNote The XML schemas define the use of {@code "never"}, which corresponds + * to the removed {@code FlushMode#NEVER}. Here we will also remap + * {@code FlushMode#NEVER} to {@link 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-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/GenerationTimingMarshalling.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/GenerationTimingMarshalling.java new file mode 100644 index 0000000..8b91e6a --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/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.internal; + +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 name == null ? null : GenerationTiming.parseFromName( name ); + } + + public static String toXml(GenerationTiming generationTiming) { + return ( null == generationTiming ) ? + null : + generationTiming.name().toLowerCase( Locale.ENGLISH ); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/GenerationTypeMarshalling.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/GenerationTypeMarshalling.java new file mode 100644 index 0000000..85678a6 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/GenerationTypeMarshalling.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.internal; + +import jakarta.persistence.GenerationType; + +/** + * JAXB marshalling for {@link GenerationType} + * + * @author Steve Ebersole + */ +public class GenerationTypeMarshalling { + public static GenerationType fromXml(String name) { + return name == null ? null : GenerationType.valueOf( name ); + } + + public static String toXml(GenerationType generationType) { + return generationType == null ? null : generationType.name(); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/InheritanceTypeMarshalling.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/InheritanceTypeMarshalling.java new file mode 100644 index 0000000..9fa4cc5 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/InheritanceTypeMarshalling.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.internal; + +import jakarta.persistence.InheritanceType; + +/** + * JAXB marshalling for {@link InheritanceType} + * + * @author Steve Ebersole + */ +public class InheritanceTypeMarshalling { + public static InheritanceType fromXml(String name) { + return name == null ? null : InheritanceType.valueOf( name ); + } + + public static String toXml(InheritanceType inheritanceType) { + return inheritanceType == null ? null : inheritanceType.name(); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/LimitedCollectionClassificationMarshalling.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/LimitedCollectionClassificationMarshalling.java new file mode 100644 index 0000000..3b56b14 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/LimitedCollectionClassificationMarshalling.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.internal; + +import java.util.Locale; + +import org.hibernate.boot.internal.LimitedCollectionClassification; + +import jakarta.persistence.AccessType; + +/** + * JAXB marshalling for JPA's {@link AccessType} + * + * @author Steve Ebersole + */ +public class LimitedCollectionClassificationMarshalling { + public static LimitedCollectionClassification fromXml(String name) { + return name == null ? null : LimitedCollectionClassification.valueOf( name.toUpperCase( Locale.ROOT ) ); + } + + public static String toXml(LimitedCollectionClassification classification) { + return classification == null ? null : classification.name().toLowerCase( Locale.ROOT ); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/LockModeTypeMarshalling.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/LockModeTypeMarshalling.java new file mode 100644 index 0000000..f526692 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/LockModeTypeMarshalling.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.internal; + +import jakarta.persistence.LockModeType; + +/** + * JAXB marshalling for {@link LockModeType} + * + * @author Steve Ebersole + */ +public class LockModeTypeMarshalling { + public static LockModeType fromXml(String name) { + return name == null ? null : LockModeType.valueOf( name ); + } + + public static String toXml(LockModeType lockModeType) { + return lockModeType == null ? null : lockModeType.name(); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/OnDeleteActionMarshalling.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/OnDeleteActionMarshalling.java new file mode 100644 index 0000000..731e7a9 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/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.internal; + +import org.hibernate.annotations.OnDeleteAction; + +/** + * @author Steve Ebersole + */ +public class OnDeleteActionMarshalling { + public static OnDeleteAction fromXml(String name) { + return name == null ? null : OnDeleteAction.fromExternalForm( name ); + } + + public static String toXml(OnDeleteAction accessType) { + return accessType == null ? null : accessType.getAlternativeName(); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/OptimisticLockStyleMarshalling.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/OptimisticLockStyleMarshalling.java new file mode 100644 index 0000000..28060d7 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/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.internal; + +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 name == null ? null : OptimisticLockStyle.valueOf( name.toUpperCase( Locale.ENGLISH ) ); + } + + public static String toXml(OptimisticLockStyle lockMode) { + return lockMode == null ? null : lockMode.name().toLowerCase( Locale.ENGLISH ); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/ParameterModeMarshalling.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/ParameterModeMarshalling.java new file mode 100644 index 0000000..283ea47 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/ParameterModeMarshalling.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.internal; + +import jakarta.persistence.ParameterMode; + +/** + * JAXB marshalling for {@link ParameterMode} + * + * @author Steve Ebersole + */ +public class ParameterModeMarshalling { + public static ParameterMode fromXml(String name) { + return name == null ? null : ParameterMode.valueOf( name ); + } + + public static String toXml(ParameterMode parameterMode) { + return parameterMode == null ? null : parameterMode.name(); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/PolymorphismTypeMarshalling.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/PolymorphismTypeMarshalling.java new file mode 100644 index 0000000..025886c --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/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.internal; + +import org.hibernate.annotations.PolymorphismType; + +/** + * @author Steve Ebersole + */ +public class PolymorphismTypeMarshalling { + public static PolymorphismType fromXml(String value) { + return value == null ? null : PolymorphismType.fromExternalValue( value ); + } + + public static String toXml(PolymorphismType value) { + return value == null ? null : value.getExternalForm(); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/ResultCheckStyleMarshalling.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/ResultCheckStyleMarshalling.java new file mode 100644 index 0000000..5cf0cf5 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/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.internal; + +import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle; + +/** + * JAXB marshalling for {@link ExecuteUpdateResultCheckStyle} + * + * @author Steve Ebersole + */ +public class ResultCheckStyleMarshalling { + public static ExecuteUpdateResultCheckStyle fromXml(String name) { + return name == null ? null : ExecuteUpdateResultCheckStyle.fromExternalName( name ); + } + + public static String toXml(ExecuteUpdateResultCheckStyle style) { + return style == null ? null : style.externalName(); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/TemporalTypeMarshalling.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/TemporalTypeMarshalling.java new file mode 100644 index 0000000..8d310ef --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/TemporalTypeMarshalling.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.internal; + +import jakarta.persistence.TemporalType; + +/** + * JAXB marshalling for {@link TemporalType} + * + * @author Steve Ebersole + */ +public class TemporalTypeMarshalling { + public static TemporalType fromXml(String name) { + return name == null ? null : TemporalType.valueOf( name ); + } + + public static String toXml(TemporalType temporalType) { + return temporalType == null ? null : temporalType.name(); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/UuidGeneratorStyleMarshalling.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/UuidGeneratorStyleMarshalling.java new file mode 100644 index 0000000..efb7c0d --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/internal/UuidGeneratorStyleMarshalling.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.internal; + +import java.util.Locale; + +import org.hibernate.annotations.UuidGenerator; + +/** + * JAXB marshalling for {@link UuidGenerator.Style} + */ +public class UuidGeneratorStyleMarshalling { + public static UuidGenerator.Style fromXml(String name) { + return name == null ? null : UuidGenerator.Style.valueOf( name.toUpperCase( Locale.ROOT ) ); + } + + public static String toXml(UuidGenerator.Style style) { + return style == null ? null : style.name().toLowerCase( Locale.ROOT ); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbAnyMapping.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbAnyMapping.java new file mode 100644 index 0000000..7766e36 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbAnyMapping.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.spi; + +import java.util.List; + +/** + * JAXB binding interface for discriminated association based attributes (any and many-to-any) + * + * @author Steve Ebersole + */ +public interface JaxbAnyMapping extends JaxbPersistentAttribute { + /** + * Details about the logical association foreign-key + */ + Key getKey(); + + /** + * Details about the discriminator + */ + Discriminator getDiscriminator(); + + /** + * The key of a {@link JaxbAnyMapping} - 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 + */ + JaxbColumnImpl getColumn(); + + /** + * Mapping of discriminator-values to the corresponding entity names + */ + List getValueMappings(); + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbAssociationAttribute.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbAssociationAttribute.java new file mode 100644 index 0000000..e7ea8dd --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbAssociationAttribute.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.spi; + + +/** + * JAXB binding interface for association attributes (to-one and plural mappings) + * + * @author Steve Ebersole + */ +public interface JaxbAssociationAttribute extends JaxbPersistentAttribute, JaxbFetchableAttribute { + JaxbJoinTableImpl getJoinTable(); + void setJoinTable(JaxbJoinTableImpl value); + + JaxbCascadeTypeImpl getCascade(); + void setCascade(JaxbCascadeTypeImpl value); + + String getTargetEntity(); + void setTargetEntity(String value); +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbAttributesContainer.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbAttributesContainer.java new file mode 100644 index 0000000..ad73ddd --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbAttributesContainer.java @@ -0,0 +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. + */ +package org.hibernate.boot.jaxb.mapping.spi; + +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 JaxbAttributesContainer extends JaxbBaseAttributesContainer{ + List getOneToOneAttributes(); + + List getAnyMappingAttributes(); + + List getElementCollectionAttributes(); + + List getOneToManyAttributes(); + + List getManyToManyAttributes(); + + List getPluralAnyMappingAttributes(); + + List getTransients(); +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbBaseAttributesContainer.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbBaseAttributesContainer.java new file mode 100644 index 0000000..4abde9c --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbBaseAttributesContainer.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.spi; + +import java.util.List; + +/** + * @author Steve Ebersole + */ +public interface JaxbBaseAttributesContainer { + List getBasicAttributes(); + + List getEmbeddedAttributes(); + + List getManyToOneAttributes(); + + List getAnyMappingAttributes(); +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbBasicMapping.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbBasicMapping.java new file mode 100644 index 0000000..dcbebf8 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbBasicMapping.java @@ -0,0 +1,39 @@ +/* + * 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.spi; + +/** + * A model part that is (or can be) basic-valued - {@linkplain JaxbIdImpl}, {@linkplain JaxbBasicImpl} and + * {@linkplain JaxbElementCollectionImpl} + * + * @author Steve Ebersole + */ +public interface JaxbBasicMapping { + JaxbUserTypeImpl getType(); + + void setType(JaxbUserTypeImpl value); + + String getTarget(); + + void setTarget(String value); + + String getJavaType(); + + void setJavaType(String value); + + String getJdbcType(); + + void setJdbcType(String value); + + Integer getJdbcTypeCode(); + + void setJdbcTypeCode(Integer value); + + String getJdbcTypeName(); + + void setJdbcTypeName(String value); +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbDiscriminatorMapping.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbDiscriminatorMapping.java new file mode 100644 index 0000000..ba91542 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbDiscriminatorMapping.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.spi; + +/** + * Mapping of a discriminator value to the corresponding entity-name + * + * @author Steve Ebersole + */ +public interface JaxbDiscriminatorMapping { + String getDiscriminatorValue(); + String getCorrespondingEntityName(); +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbEmbeddable.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbEmbeddable.java new file mode 100644 index 0000000..a7629c7 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbEmbeddable.java @@ -0,0 +1,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 http://www.gnu.org/licenses/lgpl-2.1.html. + */ +package org.hibernate.boot.jaxb.mapping.spi; + +/** + * @author Steve Ebersole + */ +public interface JaxbEmbeddable extends JaxbManagedType { +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbEmbeddedMapping.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbEmbeddedMapping.java new file mode 100644 index 0000000..a0fefb8 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbEmbeddedMapping.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.spi; + +/** + * A model part that is (or can be) embeddable-valued (composite) - {@linkplain JaxbEmbeddedIdImpl}, + * {@linkplain JaxbEmbeddedIdImpl} and {@linkplain JaxbElementCollectionImpl} + * + * @author Steve Ebersole + */ +public interface JaxbEmbeddedMapping { +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbEntity.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbEntity.java new file mode 100644 index 0000000..f7595ce --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbEntity.java @@ -0,0 +1,128 @@ +/* + * 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.spi; + +import java.util.List; + +import org.hibernate.annotations.PolymorphismType; +import org.hibernate.engine.OptimisticLockStyle; + +/** + * @author Steve Ebersole + */ +public interface JaxbEntity extends JaxbEntityOrMappedSuperclass { + String getName(); + void setName(String name); + + JaxbTableImpl getTable(); + void setTable(JaxbTableImpl value); + + String getTableExpression(); + void setTableExpression(String value); + + List getSecondaryTables(); + List getSynchronizeTables(); + + List getPrimaryKeyJoinColumns(); + + JaxbForeignKeyImpl getPrimaryKeyForeignKey(); + void setPrimaryKeyForeignKey(JaxbForeignKeyImpl value); + + String getRowid(); + void setRowid(String value); + + String getWhere(); + void setWhere(String value); + + JaxbCustomLoaderImpl getLoader(); + void setLoader(JaxbCustomLoaderImpl value); + + JaxbCustomSqlImpl getSqlInsert(); + void setSqlInsert(JaxbCustomSqlImpl value); + + JaxbCustomSqlImpl getSqlUpdate(); + void setSqlUpdate(JaxbCustomSqlImpl value); + + JaxbCustomSqlImpl getSqlDelete(); + void setSqlDelete(JaxbCustomSqlImpl value); + + Boolean isDynamicInsert(); + void setDynamicInsert(Boolean value); + + Boolean isDynamicUpdate(); + void setDynamicUpdate(Boolean value); + + Boolean isSelectBeforeUpdate(); + void setSelectBeforeUpdate(Boolean value); + + JaxbCachingImpl getCaching(); + void setCaching(JaxbCachingImpl value); + + Integer getBatchSize(); + void setBatchSize(Integer value); + + Boolean isLazy(); + void setLazy(Boolean value); + + Boolean isMutable(); + void setMutable(Boolean value); + + OptimisticLockStyle getOptimisticLock(); + void setOptimisticLock(OptimisticLockStyle value); + + JaxbInheritanceImpl getInheritance(); + void setInheritance(JaxbInheritanceImpl value); + + String getProxy(); + void setProxy(String value); + + PolymorphismType getPolymorphism(); + void setPolymorphism(PolymorphismType value); + + String getDiscriminatorValue(); + void setDiscriminatorValue(String value); + + JaxbDiscriminatorColumnImpl getDiscriminatorColumn(); + void setDiscriminatorColumn(JaxbDiscriminatorColumnImpl value); + + String getDiscriminatorFormula(); + void setDiscriminatorFormula(String value); + + JaxbSequenceGeneratorImpl getSequenceGenerator(); + void setSequenceGenerator(JaxbSequenceGeneratorImpl value); + + JaxbTableGeneratorImpl getTableGenerator(); + void setTableGenerator(JaxbTableGeneratorImpl value); + + List getIdentifierGenerator(); + + List getNamedQueries(); + List getNamedNativeQueries(); + List getNamedStoredProcedureQueries(); + List getSqlResultSetMappings(); + + List getAttributeOverrides(); + List getAssociationOverrides(); + + List getConverts(); + + List getNamedEntityGraphs(); + + List getFilters(); + + List getFetchProfiles(); + + JaxbTenantIdImpl getTenantId(); + void setTenantId(JaxbTenantIdImpl value); + + JaxbAttributesContainerImpl getAttributes(); + void setAttributes(JaxbAttributesContainerImpl value); + + Boolean isCacheable(); + void setCacheable(Boolean value); + +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbEntityOrMappedSuperclass.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbEntityOrMappedSuperclass.java new file mode 100644 index 0000000..568c39a --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbEntityOrMappedSuperclass.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.mapping.spi; + +/** + * JAXB binding interface for commonality between entity and mapped-superclass mappings + * + * @author Steve Ebersole + */ +public interface JaxbEntityOrMappedSuperclass extends JaxbManagedType, JaxbLifecycleCallbackContainer { + JaxbIdClassImpl getIdClass(); + + void setIdClass(JaxbIdClassImpl value); + + JaxbEmptyTypeImpl getExcludeDefaultListeners(); + + void setExcludeDefaultListeners(JaxbEmptyTypeImpl value); + + JaxbEmptyTypeImpl getExcludeSuperclassListeners(); + + void setExcludeSuperclassListeners(JaxbEmptyTypeImpl value); + + JaxbEntityListenersImpl getEntityListeners(); + + void setEntityListeners(JaxbEntityListenersImpl value); +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbFetchableAttribute.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbFetchableAttribute.java new file mode 100644 index 0000000..885e5f2 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbFetchableAttribute.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.spi; + +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 JaxbFetchableAttribute extends JaxbPersistentAttribute { + FetchType getFetch(); + void setFetch(FetchType value); +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbLifecycleCallback.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbLifecycleCallback.java new file mode 100644 index 0000000..3160d84 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbLifecycleCallback.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.spi; + +/** + * JAXB binding interface for lifecycle callbacks. + * + * @author Strong Liu + * @author Steve Ebersole + */ +public interface JaxbLifecycleCallback { + String getMethodName(); +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbLifecycleCallbackContainer.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbLifecycleCallbackContainer.java new file mode 100644 index 0000000..e72e853 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbLifecycleCallbackContainer.java @@ -0,0 +1,43 @@ +/* + * 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.spi; + +/** + * 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 JaxbLifecycleCallbackContainer { + JaxbPrePersistImpl getPrePersist(); + void setPrePersist(JaxbPrePersistImpl value); + + JaxbPostPersistImpl getPostPersist(); + void setPostPersist(JaxbPostPersistImpl value); + + JaxbPreRemoveImpl getPreRemove(); + void setPreRemove(JaxbPreRemoveImpl value); + + JaxbPostRemoveImpl getPostRemove(); + void setPostRemove(JaxbPostRemoveImpl value); + + JaxbPreUpdateImpl getPreUpdate(); + void setPreUpdate(JaxbPreUpdateImpl value); + + JaxbPostUpdateImpl getPostUpdate(); + void setPostUpdate(JaxbPostUpdateImpl value); + + JaxbPostLoadImpl getPostLoad(); + void setPostLoad(JaxbPostLoadImpl value); +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbManagedType.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbManagedType.java new file mode 100644 index 0000000..8bc84c7 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbManagedType.java @@ -0,0 +1,32 @@ +/* + * 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.spi; + +import jakarta.persistence.AccessType; + +/** + * Common interface for JAXB bindings representing entities, mapped-superclasses and embeddables (JPA collective + * calls these "managed types" in terms of its Metamodel api). + * + * @author Strong Liu + * @author Steve Ebersole + */ +public interface JaxbManagedType { + String getClazz(); + void setClazz(String className); + + Boolean isMetadataComplete(); + void setMetadataComplete(Boolean isMetadataComplete); + + AccessType getAccess(); + void setAccess(AccessType value); + + String getDescription(); + void setDescription(String value); + + JaxbAttributesContainer getAttributes(); +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbMappedSuperclass.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbMappedSuperclass.java new file mode 100644 index 0000000..f057c32 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbMappedSuperclass.java @@ -0,0 +1,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 http://www.gnu.org/licenses/lgpl-2.1.html. + */ +package org.hibernate.boot.jaxb.mapping.spi; + +/** + * @author Steve Ebersole + */ +public interface JaxbMappedSuperclass extends JaxbEntityOrMappedSuperclass { +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbNamedQuery.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbNamedQuery.java new file mode 100644 index 0000000..1954a59 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbNamedQuery.java @@ -0,0 +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. + */ +package org.hibernate.boot.jaxb.mapping.spi; + +import java.io.Serializable; +import java.util.List; + +import jakarta.persistence.LockModeType; + +public interface JaxbNamedQuery extends Serializable { + String getName(); + void setName(String value); + + String getDescription(); + void setDescription(String value); + + String getQuery(); + void setQuery(String value); + + String getComment(); + void setComment(String comment); + + Integer getTimeout(); + void setTimeout(Integer timeout); + + LockModeType getLockMode(); + void setLockMode(LockModeType value); + + List getHint(); +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbNaturalId.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbNaturalId.java new file mode 100644 index 0000000..4b70c5d --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbNaturalId.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.spi; + +/** + * JAXB binding interface for natural-id definitions + * + * @author Steve Ebersole + */ +public interface JaxbNaturalId extends JaxbBaseAttributesContainer{ + /** + * The cache config associated with this natural-id + */ + JaxbCachingImpl getCaching(); + + boolean isMutable(); + void setMutable(Boolean mutable); +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbNotFoundCapable.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbNotFoundCapable.java new file mode 100644 index 0000000..dfdd9d3 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbNotFoundCapable.java @@ -0,0 +1,15 @@ +/* + * 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.spi; + +/** + * @author Steve Ebersole + */ +public interface JaxbNotFoundCapable extends JaxbPersistentAttribute { + JaxbNotFoundEnumImpl getNotFound(); + void setNotFound(JaxbNotFoundEnumImpl value); +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbPersistentAttribute.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbPersistentAttribute.java new file mode 100644 index 0000000..d74643c --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbPersistentAttribute.java @@ -0,0 +1,35 @@ +/* + * 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.spi; + +import jakarta.persistence.AccessType; + +/** + * Common interface for JAXB bindings that represent persistent attributes. + * + * @author Strong Liu + * @author Steve Ebersole + */ +public interface JaxbPersistentAttribute { + /** + * 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-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbPluralAttribute.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbPluralAttribute.java new file mode 100644 index 0000000..dd9b9cb --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbPluralAttribute.java @@ -0,0 +1,68 @@ +/* + * 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.spi; + +import java.util.List; + +import org.hibernate.boot.internal.LimitedCollectionClassification; + +import jakarta.persistence.EnumType; +import jakarta.persistence.TemporalType; + +/** + * JAXB binding interface for plural attributes + * + * @author Brett Meyer + */ +public interface JaxbPluralAttribute extends JaxbFetchableAttribute { + JaxbPluralFetchModeImpl getFetchMode(); + void setFetchMode(JaxbPluralFetchModeImpl mode); + + JaxbCollectionIdImpl getCollectionId(); + void setCollectionId(JaxbCollectionIdImpl id); + + + LimitedCollectionClassification getClassification(); + void setClassification(LimitedCollectionClassification value); + + String getOrderBy(); + void setOrderBy(String value); + + JaxbOrderColumnImpl getOrderColumn(); + void setOrderColumn(JaxbOrderColumnImpl value); + + String getSort(); + void setSort(String value); + + JaxbMapKeyImpl getMapKey(); + void setMapKey(JaxbMapKeyImpl value); + + JaxbMapKeyClassImpl getMapKeyClass(); + void setMapKeyClass(JaxbMapKeyClassImpl value); + + TemporalType getMapKeyTemporal(); + + void setMapKeyTemporal(TemporalType value); + + EnumType getMapKeyEnumerated(); + + void setMapKeyEnumerated(EnumType value); + + List getMapKeyAttributeOverride(); + + List getMapKeyConvert(); + + JaxbMapKeyColumnImpl getMapKeyColumn(); + + void setMapKeyColumn(JaxbMapKeyColumnImpl value); + + List getMapKeyJoinColumn(); + + JaxbForeignKeyImpl getMapKeyForeignKey(); + + void setMapKeyForeignKey(JaxbForeignKeyImpl value); +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbSchemaAware.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbSchemaAware.java new file mode 100644 index 0000000..9249b66 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbSchemaAware.java @@ -0,0 +1,21 @@ +/* + * 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.spi; + +/** + * Common interface for JAXB bindings that understand database schema (tables, sequences, etc). + * + * @author Strong Liu + * @author Steve Ebersole + */ +public interface JaxbSchemaAware { + String getSchema(); + void setSchema(String schema); + + String getCatalog(); + void setCatalog(String catalog); +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbToOneAttribute.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbToOneAttribute.java new file mode 100644 index 0000000..f252013 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbToOneAttribute.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.spi; + +/** + * @author Steve Ebersole + */ +public interface JaxbToOneAttribute extends JaxbAssociationAttribute { + JaxbSingularFetchModeImpl getFetchMode(); + + void setFetchMode(JaxbSingularFetchModeImpl mode); +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/spi/Binder.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/spi/Binder.java new file mode 100644 index 0000000..6e27b12 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/spi/Binder.java @@ -0,0 +1,37 @@ +/* + * 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; + +import java.io.InputStream; +import javax.xml.transform.Source; + +import org.hibernate.boot.jaxb.Origin; + +/** + * Contract for performing JAXB binding. + * + * @author Steve Ebersole + */ +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); + + /** + * 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); +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/spi/Binding.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/spi/Binding.java new file mode 100644 index 0000000..c7b15bb --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/spi/Binding.java @@ -0,0 +1,46 @@ +/* + * 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.spi; + +import java.io.Serializable; + +import org.hibernate.boot.jaxb.Origin; + +/** + * Represents a JAXB binding, as well as keeping information about the origin + * of the processed XML + * + * @author Steve Ebersole + * @author Hardy Ferentschik + */ +public class Binding implements Serializable { + private final T root; + private final Origin origin; + + public Binding(T root, Origin origin) { + this.root = root; + this.origin = origin; + } + + /** + * Obtain the root JAXB bound object + * + * @return The JAXB root object + */ + public T getRoot() { + return root; + } + + /** + * Obtain the metadata about the document's origin + * + * @return The origin + */ + public Origin getOrigin() { + return origin; + } +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/spi/JaxbBindableMappingDescriptor.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/spi/JaxbBindableMappingDescriptor.java new file mode 100644 index 0000000..969b254 --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/spi/JaxbBindableMappingDescriptor.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 JaxbBindableMappingDescriptor { +} diff --git a/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/spi/XmlSource.java b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/spi/XmlSource.java new file mode 100644 index 0000000..8d81fcf --- /dev/null +++ b/hibernate-orm/src/main/java/org/hibernate/boot/jaxb/spi/XmlSource.java @@ -0,0 +1,32 @@ +/* + * 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.spi; + +import org.hibernate.boot.jaxb.Origin; + +/** + * An XML document containing O/R mapping metadata, either: + *
    + *
  • a JPA {@code orm.xml} file, or + *
  • a Hibernate {@code .hbm.xml} file. + *
+ * + * @author Steve Ebersole + */ +public abstract class XmlSource { + private final Origin origin; + + protected XmlSource(Origin origin) { + this.origin = origin; + } + + public Origin getOrigin() { + return origin; + } + + public abstract Binding doBind(Binder binder); +} diff --git a/hibernate-orm/src/main/resources/org/hibernate/xsd/mapping/mapping-3.1.0.xsd b/hibernate-orm/src/main/resources/org/hibernate/xsd/mapping/mapping-3.1.0.xsd new file mode 100644 index 0000000..4838898 --- /dev/null +++ b/hibernate-orm/src/main/resources/org/hibernate/xsd/mapping/mapping-3.1.0.xsd @@ -0,0 +1,3029 @@ + + + + + + + + ... + + ]]> + + + + + + + + + + + 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. 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 + the entity, mapped-superclass and embeddable elements defined in + the same file in which they occur. + + 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. 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. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + See @JavaTypeRegistration + + + + + + + + + + See @JdbcTypeRegistration + + + + + + + + + + See @TypeRegistration + + + + + + + + + + See @CompositeTypeRegistration + + + + + + + + + + See @CollectionTypeRegistration + + + + + + + + + + + + + Configuration parameter user-types + + + + + + + + + + See `org.hibernate.metamodel.CollectionClassification` + + + + + + + + + + + + + + + + + + + + See @ConverterRegistration + + + + + + + + + + + See @EmbeddableInstantiatorRegistration + + + + + + + + + + + + + + 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. + + + + + + + + + + + + + + + + + + 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. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 ""; + } + + may be used to model both typed and dynamic models - + 1. a dynamic model is represented as a Map and is indicated by - + a. metadata-complete + b. class is empty + c. name is the "entity name" (hbm sense, rather than @Entity#name) + 2. typed model has a mapped class + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + See `@org.hibernate.boot.internal.Abstract` + + + + + + + See `@org.hibernate.boot.internal.Extends` + + + + + + + + + + + + + + + + + + + + + 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` + + + + + + + + + + + + + + + + + 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. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + See `org.hibernate.annotations.GenerationTime` + See `org.hibernate.tuple.GenerationTiming` + See `@org.hibernate.annotations.Generated` + + + + + + + + + + + + + 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` + See `@org.hibernate.annotations.Type` + See `@org.hibernate.annotations.JavaType` + See `@org.hibernate.annotations.JdbcTypeCode` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + See @org.hibernate.annotations.Target + + Generally only useful for dynamic-models - specifies the attribute's Java type + + + + + + + @org.hibernate.annotations.JavaType + + + + + + + + + @org.hibernate.annotations.JdbcType + + + + + + + @org.hibernate.annotations.JdbcTypeCode + + + + + + + Name from org.hibernate.type.SqlTypes + + + + + + + + + + + + + + + See `@jakarta.persistence.CollectionTable` + + + + + + + + + + + + + + + + + + + + + + See `@jakarta.persistence.ColumnResult` + + + + + + + + + + + + See `jakarta.persistence.ConstraintMode` + + + + + + + + + + + + + + + + + + + See `@jakarta.persistence.ConstructorResult` + + + + + + + + + + + + + + See `@jakarta.persistence.DiscriminatorColumn` + See `@org.hibernate.annotations.DiscriminatorOptions` + + + + + + + + + + + + + + + + See `jakarta.persistence.DiscriminatorType` + + + + + + + + + + + + + + + See `jakarta.persistence.DiscriminatorValue + + + + + + + + + + + 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` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + See `@org.hibernate.annotations.CollectionId` + See `@org.hibernate.annotations.CollectionIdType` + See `@org.hibernate.annotations.CollectionIdJavaType` + See `@org.hibernate.annotations.CollectionIdJdbcType` + See `@org.hibernate.annotations.CollectionIdJdbcTypeCode` + + + + + + + + + + + + + See `@org.hibernate.boot.internal.CollectionClassification`. + + Defines a limited set of `org.hibernate.metamodel.CollectionClassification`. + + We leave off the following enumerated values, since we can distinguish those already + via presence of , , and - + * ID_BAG + * SORTED_SET + * ORDERED_SET + * SORTED_MAP + * ORDERED_MAP + + ARRAY is also missing, as handling the element type is tricky. + + + + + + + + + + + + + + + + + + + + + + + See `@jakarta.persistence.Embeddable` + + + + + + + + + + + + + + + + + + + + Describes the features available for mapping attributes of embeddables + + + + + + + + + + + + + + + + + + + + + + + + See `@jakarta.persistence.Embedded` + See `@org.hibernate.annotations.AttributeAccessor` + See `@org.hibernate.annotations.OptimisticLock` + + + + + + + See `@org.hibernate.boot.internal.Target` + + + + + + + + + + + + + + + + + + + See `@jakarta.persistence.EmbeddedId` + See `@org.hibernate.annotations.AttributeAccessor` + + + + + + + + + + + + + + + + + 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` + + + + + + + + + + + + + + + + + + + + + See `@jakarta.persistence.EntityListeners` + + + + + + + + + + + + + See `@jakarta.persistence.EntityResult` + + + + + + + + + + + + + + + + See `jakarta.persistence.EnumType` + + + + + + + + + + + + + + See `@jakarta.persistence.Enumerated` + + + + + + + + + + + See `jakarta.persistence.FetchType` + + + + + + + + + + + + + + See `@jakarta.persistence.FieldResult` + + + + + + + + + + + + See `@jakarta.persistence.ForeignKey` + + + + + + + + + + + + + + + + See `@jakarta.persistence.GeneratedValue` + + + + + + + + + + + + See `jakarta.persistence.GenerationType` + + + + + + + + + + + + + + + + + See `@jakarta.persistence.Id` + See `@org.hibernate.annotations.AttributeAccessor` + See `@org.hibernate.annotations.Type` + See `@org.hibernate.annotations.JdbcTypeCode` + See `@org.hibernate.annotations.UuidGenerator` + + + + + + + + + + + + + + + + + + + + + + + + + + + + See `@jakarta.persistence.IdClass` + + + + + + + + + + + See `jakarta.persistence.Index` + + + + + + + + + + + + + + + + See `@jakarta.persistence.Inheritance` + + + + + + + + + + + See `jakarta.persistence.InheritanceType + + + + + + + + + + + + + + + See `@jakarta.persistence.JoinColumn` + + + + + + + + + + + + + + + + + + See `@jakarta.persistence.JoinTable` + + + + + + + + + + + + + + + + + + + + + + + + + + See `jakarta.persistence.Lob` + + + + + + + + + + See `javax.persistence.LockModeType` + + + + + + + + + + + + + + + + + + + + + + See `@jakarta.persistence.ManyToMany` + + See `@org.hibernate.annotations.SortComparator` + See `@org.hibernate.annotations.SortNatural` + See `@org.hibernate.annotations.AttributeAccessor` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + See `@jakarta.persistence.ManyToOne` + + See `@org.hibernate.annotations.AttributeAccessor` + See `@org.hibernate.annotations.OnDelete + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + See `@jakarta.persistence.MapKey` + + + + + + + + + + + See `@jakarta.persistence.MapKeyClass` + + + + + + + + + + + See `@jakarta.persistence.MapKeyColumn` + + + + + + + + + + + + + + + + + + + + See `@jakarta.persistence.MapKeyJoinColumn` + + + + + + + + + + + + + + + + + + + See `@jakarta.persistence.MappedSuperclass` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @Target({}) @Retention(RUNTIME) + public @interface NamedAttributeNode { + String value(); + String subgraph() default ""; + String keySubgraph() default ""; + } + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface NamedEntityGraph { + String name() default ""; + NamedAttributeNode[] attributeNodes() default {}; + boolean includeAllAttributes() default false; + NamedSubgraph[] subgraphs() default {}; + NamedSubGraph[] subclassSubgraphs() default {}; + } + + + + + + + + + + + + + + + + + + + + @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. + + todo : a lot of these extensions could be handled by JPA QueryHint scheme + + + + + + + + + + + + + + + + + + + + + + + + + + Used only by tools to generate finder methods for named queries + + + + + + + + + + + + + + + @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(); + } + + + + + + + + + + + + + + + + + + @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; + } + + + + + + + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface SqlResultSetMapping { + String name(); + EntityResult[] entities() default {}; + ConstructorResult[] classes() default{}; + ColumnResult[] columns() default {}; + } + + + + + + + + + + + + + + + + + + + @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` + + + + + + + + + + + + + + + + @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 {}; + } + + + + + + + + + + + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface Temporal { + TemporalType value(); + } + + + + + + + + + + + + + public enum TemporalType { + DATE, // java.sql.Date + TIME, // java.sql.Time + TIMESTAMP // java.sql.Timestamp + } + + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface Transient {} + + + + + + + + + + + + + @Target({}) @Retention(RUNTIME) + public @interface UniqueConstraint { + String name() default ""; + String[] columnNames(); + } + + + + + + + + + + + + + + + + @Target({METHOD, FIELD}) @Retention(RUNTIME) + public @interface Version {} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Specifies a filter definition. After definition, a filter + can be applied to entity or collection by name. + + + + + + + + + Used to identify all bind parameters in the condition elemement + + + + + + + + + + + + + + + + Applies a filter defined by hbm-filter-def usage + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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) + as well as any configuration information need by the implementation (Hibernate + will pass it the parameters after instantiation). + + + + + + + + + + + + + + + + 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 + an entity or collection + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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). + + + + + + + + + + + com.acme.Employee + ]]> + + + + + + + + + + + + + + + See `@org.hibernate.annotations.ManyToAny` + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + + + + + + + + + + + + + See `@org.hibernate.annotations.Type` + + + + + + + + + + + + + + org.hibernate.annotations.UuidGenerator.Style enum values + + + + + + + + + + + + + See `@org.hibernate.annotations.UuidGenerator` + + + + + + diff --git a/hibernate-orm/src/main/xjb/mapping-bindings.xjb b/hibernate-orm/src/main/xjb/mapping-bindings.xjb new file mode 100644 index 0000000..cdcf78f --- /dev/null +++ b/hibernate-orm/src/main/xjb/mapping-bindings.xjb @@ -0,0 +1,569 @@ + + + + + + + + + + + + + + + + + org.hibernate.boot.jaxb.spi.JaxbBindableMappingDescriptor + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbEntity + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbEmbeddable + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbMappedSuperclass + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbAttributesContainer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbAttributesContainer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbPersistentAttribute + org.hibernate.boot.jaxb.mapping.spi.JaxbBasicMapping + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbPersistentAttribute + org.hibernate.boot.jaxb.mapping.spi.JaxbEmbeddedMapping + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbPersistentAttribute + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbPersistentAttribute + org.hibernate.boot.jaxb.mapping.spi.JaxbBasicMapping + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbPersistentAttribute + org.hibernate.boot.jaxb.mapping.spi.JaxbEmbeddedMapping + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbToOneAttribute + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbToOneAttribute + org.hibernate.boot.jaxb.mapping.spi.JaxbNotFoundCapable + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbAnyMapping + + + + + + + + + + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbPluralAttribute + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbPluralAttribute + org.hibernate.boot.jaxb.mapping.spi.JaxbAssociationAttribute + org.hibernate.boot.jaxb.mapping.spi.JaxbNotFoundCapable + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbPluralAttribute + org.hibernate.boot.jaxb.mapping.spi.JaxbAssociationAttribute + org.hibernate.boot.jaxb.mapping.spi.JaxbNotFoundCapable + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbAnyMapping + + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbAnyMapping.Discriminator + + + + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbDiscriminatorMapping + + + + + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbAnyMapping.Key + + + + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbNaturalId + + + + + + + + + + + + + + + + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbSchemaAware + + + org.hibernate.boot.jaxb.mapping.spi.JaxbSchemaAware + + + org.hibernate.boot.jaxb.mapping.spi.JaxbSchemaAware + + + org.hibernate.boot.jaxb.mapping.spi.JaxbSchemaAware + + + org.hibernate.boot.jaxb.mapping.spi.JaxbSchemaAware + + + org.hibernate.boot.jaxb.mapping.spi.JaxbSchemaAware + + + + + + + + + + + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbLifecycleCallbackContainer + + + + org.hibernate.boot.jaxb.mapping.spi.JaxbLifecycleCallback + + + org.hibernate.boot.jaxb.mapping.spi.JaxbLifecycleCallback + + + org.hibernate.boot.jaxb.mapping.spi.JaxbLifecycleCallback + + + org.hibernate.boot.jaxb.mapping.spi.JaxbLifecycleCallback + + + org.hibernate.boot.jaxb.mapping.spi.JaxbLifecycleCallback + + + org.hibernate.boot.jaxb.mapping.spi.JaxbLifecycleCallback + + + org.hibernate.boot.jaxb.mapping.spi.JaxbLifecycleCallback + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/patched-libs/jaxb2-basics/jaxb2-basics-ant-patched-sources.jar b/patched-libs/jaxb2-basics/jaxb2-basics-ant-patched-sources.jar new file mode 100644 index 0000000..3cdd2a9 Binary files /dev/null and b/patched-libs/jaxb2-basics/jaxb2-basics-ant-patched-sources.jar differ diff --git a/patched-libs/jaxb2-basics/jaxb2-basics-ant-patched.jar b/patched-libs/jaxb2-basics/jaxb2-basics-ant-patched.jar new file mode 100644 index 0000000..f1fbce6 Binary files /dev/null and b/patched-libs/jaxb2-basics/jaxb2-basics-ant-patched.jar differ diff --git a/patched-libs/jaxb2-basics/jaxb2-basics-patched-sources.jar b/patched-libs/jaxb2-basics/jaxb2-basics-patched-sources.jar new file mode 100644 index 0000000..f04c832 Binary files /dev/null and b/patched-libs/jaxb2-basics/jaxb2-basics-patched-sources.jar differ diff --git a/patched-libs/jaxb2-basics/jaxb2-basics-patched.jar b/patched-libs/jaxb2-basics/jaxb2-basics-patched.jar new file mode 100644 index 0000000..e9ad751 Binary files /dev/null and b/patched-libs/jaxb2-basics/jaxb2-basics-patched.jar differ diff --git a/patched-libs/jaxb2-basics/jaxb2-basics-plugins-patched-sources.jar b/patched-libs/jaxb2-basics/jaxb2-basics-plugins-patched-sources.jar new file mode 100644 index 0000000..319d896 Binary files /dev/null and b/patched-libs/jaxb2-basics/jaxb2-basics-plugins-patched-sources.jar differ diff --git a/patched-libs/jaxb2-basics/jaxb2-basics-plugins-patched.jar b/patched-libs/jaxb2-basics/jaxb2-basics-plugins-patched.jar new file mode 100644 index 0000000..f14e70f Binary files /dev/null and b/patched-libs/jaxb2-basics/jaxb2-basics-plugins-patched.jar differ diff --git a/patched-libs/jaxb2-basics/jaxb2-basics-runtime-patched-sources.jar b/patched-libs/jaxb2-basics/jaxb2-basics-runtime-patched-sources.jar new file mode 100644 index 0000000..8cf2f8b Binary files /dev/null and b/patched-libs/jaxb2-basics/jaxb2-basics-runtime-patched-sources.jar differ diff --git a/patched-libs/jaxb2-basics/jaxb2-basics-runtime-patched.jar b/patched-libs/jaxb2-basics/jaxb2-basics-runtime-patched.jar new file mode 100644 index 0000000..42a37cc Binary files /dev/null and b/patched-libs/jaxb2-basics/jaxb2-basics-runtime-patched.jar differ diff --git a/patched-libs/jaxb2-basics/jaxb2-basics-tools-patched-sources.jar b/patched-libs/jaxb2-basics/jaxb2-basics-tools-patched-sources.jar new file mode 100644 index 0000000..7e8d38c Binary files /dev/null and b/patched-libs/jaxb2-basics/jaxb2-basics-tools-patched-sources.jar differ diff --git a/patched-libs/jaxb2-basics/jaxb2-basics-tools-patched.jar b/patched-libs/jaxb2-basics/jaxb2-basics-tools-patched.jar new file mode 100644 index 0000000..cbfad6b Binary files /dev/null and b/patched-libs/jaxb2-basics/jaxb2-basics-tools-patched.jar differ diff --git a/settings.gradle b/settings.gradle index d79f231..91e204c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,11 @@ -rootProject.name = 'hibernate-models2' +pluginManagement { + repositories { + gradlePluginPortal() + mavenCentral() + } +} +rootProject.name = 'hibernate-models2' dependencyResolutionManagement { repositories { @@ -26,7 +32,7 @@ dependencyResolutionManagement { def classmateVersion = version "classmate", "1.5.1" library( "classmate", "com.fasterxml", "classmate" ).versionRef( classmateVersion ) - def hibernateVersion = version "hibernateOrm", "7.0.0-SNAPSHOT" + def hibernateVersion = version "hibernateOrm", "6.3.0.Final" // withoutVersion assuming that the platform is applied library( "hibernateCore", "org.hibernate.orm", "hibernate-core" ).withoutVersion() library( "hibernatePlatform", "org.hibernate.orm", "hibernate-platform" ).versionRef( hibernateVersion ) @@ -39,39 +45,34 @@ dependencyResolutionManagement { def jandexVersion = version "jandex", "3.1.2" library( "jandex", "io.smallrye", "jandex" ).versionRef( jandexVersion ) - def jaxbApiVersion = version "jaxbApi", "4.0.0" - library( "jaxbApi", "jakarta.xml.bind", "jakarta.xml.bind-api" ).versionRef( jaxbApiVersion ) - - def jaxbRuntimeVersion = version "jaxbRuntime", "4.0.2" - library( "jaxb", "org.glassfish.jaxb", "jaxb-runtime" ).versionRef( jaxbRuntimeVersion ) - - def jpaVersion = version "jpaRuntime", "3.1.0" - library( "jpa", "jakarta.persistence", "jakarta.persistence-api" ).versionRef( jpaVersion ) - def jbossLoggingVersion = version "jbossLogging", "3.5.0.Final" library( "logging", "org.jboss.logging", "jboss-logging" ).versionRef( jbossLoggingVersion ) def jbossLoggingToolVersion = version "jbossLoggingTool", "2.2.1.Final" library( "loggingAnnotations", "org.jboss.logging", "jboss-logging-annotations" ).versionRef( jbossLoggingToolVersion ) library( "loggingProcessor", "org.jboss.logging", "jboss-logging-processor" ).versionRef( jbossLoggingToolVersion ) + } + jakartaLibs { + def jpaVersion = version "jpaRuntime", "3.1.0" + library( "jpa", "jakarta.persistence", "jakarta.persistence-api" ).versionRef( jpaVersion ) - def jsonbApiVersion = version "jsonbApi", "3.0.0" - library( "jsonbApi", "jakarta.json.bind", "jakarta.json.bind-api" ).versionRef( jsonbApiVersion ) + def injectVersion = version "inject", "2.0.1" + def jaxbApiVersion = version "jaxbApi", "4.0.0" + def jaxbRuntimeVersion = version "jaxbRuntime", "4.0.2" + library( "inject", "jakarta.inject", "jakarta.inject-api" ).versionRef( injectVersion ) + library( "jaxbApi", "jakarta.xml.bind", "jakarta.xml.bind-api" ).versionRef( jaxbApiVersion ) + library( "jaxb", "org.glassfish.jaxb", "jaxb-runtime" ).versionRef( jaxbRuntimeVersion ) + library( "xjc", "org.glassfish.jaxb", "jaxb-xjc" ).versionRef( jaxbRuntimeVersion ) + def jsonbApiVersion = version "jsonbApi", "3.0.0" def jsonbRuntimeVersion = version "jsonbRuntime", "3.0.2" + library( "jsonbApi", "jakarta.json.bind", "jakarta.json.bind-api" ).versionRef( jsonbApiVersion ) library( "jsonb", "org.eclipse", "yasson" ).versionRef( jsonbRuntimeVersion ) - - def xjcVersion = version "jaxbRuntime", jaxbRuntimeVersion - library( "xjc", "org.glassfish.jaxb", "jaxb-xjc" ).versionRef( xjcVersion ) } - testLibs { def assertjVersion = version "assertj", "3.22.0" library( "assertjCore", "org.assertj", "assertj-core" ).versionRef( assertjVersion ) - def jpaVersion = version "jpa", "3.1.0" - library( "jpa", "jakarta.persistence", "jakarta.persistence-api" ).versionRef( jpaVersion ) - def junit5Version = version "junit5", "5.9.2" library( "junit5Api", "org.junit.jupiter", "junit-jupiter-api" ).versionRef( junit5Version ) library( "junit5Engine", "org.junit.jupiter", "junit-jupiter-engine" ).versionRef( junit5Version ) @@ -88,6 +89,7 @@ include "hibernate-models-common" include "hibernate-models-source" include "hibernate-models-orm" include "hibernate-models-testing" +include "hibernate-orm" rootProject.children.each { project -> project.buildFileName = "${project.name}.gradle" diff --git a/todos.adoc b/todos.adoc index fb12a0f..4e17ad0 100644 --- a/todos.adoc +++ b/todos.adoc @@ -1,9 +1,20 @@ -= Open Questions and To-do items += Stuff + +== Open Questions * Hierarchical packages? E.g. should things defined on the `com.acme` package apply to things in the `com.acme.model` package? Should `PackageDetails` have reference to its "parent" `PackageDetails`? -* [.line-through]#Model `AnnotationAttributeValue`? Dropped that here from earlier iterations - its only real benefit was to help model the idea of implicit (unspecified) values. But since the quorum is to simply follow JLS, "this is the way". It simplifies the code quite a bit and imo only makes sense if we want to be able to model that implicitness aspect# - Dropped `AnnotationAttributeValue` -* Support ``? "Needed" for dynamic models and inheritance (if that's something we want to support). Will also need a (internal) annotation -* Allow mapped-superclass in dynamic models? XSD change -* [.line-through]#Support for dynamic embeddables in XSD# - see `` and `` -* [.line-through]#Update the mapping.xsd to account for new @GenericGenerator definition# -* [.line-through]#todo : we need some form of "attribute (java) type" in the XSD for dynamic models# - see the new `` element plus `target-entity` +* Allow mapped-superclass in dynamic models? +* Support for `@Comment` + + +== XML Annotations + +List of annotations I've come across as needing, mainly for dynamic models, which do not make general sense - + +* `@Abstract` +* `@Extends` +* `@CollectionClassification` +* `@Target`[1] + + +[1] org.hibernate.annotations.Target does exist, but is deprecated. Can either repurpose that one or create a new one along with these others. \ No newline at end of file