From 99914c259a04cb08801a89154a7e0fe1cba8b9a2 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Tue, 21 Nov 2023 11:10:06 +0100 Subject: [PATCH] #26 - Create AnnotationUsage for tenant-id in XML --- .../xml/internal/ManagedTypeProcessor.java | 47 ++++++++++ .../models/orm/xml/dynamic/TenantIdTest.java | 89 +++++++++++++++++++ .../mappings/dynamic/dynamic-tenantid.xml | 28 ++++++ 3 files changed, 164 insertions(+) create mode 100644 src/test/java/org/hibernate/models/orm/xml/dynamic/TenantIdTest.java create mode 100644 src/test/resources/mappings/dynamic/dynamic-tenantid.xml diff --git a/src/main/java/org/hibernate/boot/models/categorize/xml/internal/ManagedTypeProcessor.java b/src/main/java/org/hibernate/boot/models/categorize/xml/internal/ManagedTypeProcessor.java index 79a029b..de2acd6 100644 --- a/src/main/java/org/hibernate/boot/models/categorize/xml/internal/ManagedTypeProcessor.java +++ b/src/main/java/org/hibernate/boot/models/categorize/xml/internal/ManagedTypeProcessor.java @@ -15,6 +15,7 @@ import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.SQLInsert; import org.hibernate.annotations.SQLUpdate; +import org.hibernate.annotations.TenantId; import org.hibernate.boot.internal.Abstract; import org.hibernate.boot.internal.Extends; import org.hibernate.boot.internal.LimitedCollectionClassification; @@ -34,7 +35,9 @@ 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.boot.jaxb.mapping.spi.JaxbTenantIdImpl; import org.hibernate.boot.models.categorize.spi.JpaEventListenerStyle; +import org.hibernate.boot.models.categorize.xml.internal.attr.BasicAttributeProcessing; import org.hibernate.boot.models.categorize.xml.internal.attr.BasicIdAttributeProcessing; import org.hibernate.boot.models.categorize.xml.internal.attr.CommonAttributeProcessing; import org.hibernate.boot.models.categorize.xml.internal.attr.EmbeddedIdAttributeProcessing; @@ -218,6 +221,22 @@ private static void prepareDynamicClass( classDetails.addField( member ); } ); } + + // + final JaxbTenantIdImpl tenantId = jaxbDynamicEntity.getTenantId(); + if ( tenantId != null ) { + final ClassDetails attributeJavaType = determineDynamicAttributeJavaType( + tenantId, + xmlDocumentContext + ); + final MapModeFieldDetails member = new MapModeFieldDetails( + tenantId.getName(), + attributeJavaType, + MEMBER_MODIFIERS, + xmlDocumentContext.getModelBuildingContext() + ); + classDetails.addField( member ); + } } final JaxbAttributesContainer attributes = jaxbManagedType.getAttributes(); @@ -454,9 +473,37 @@ private static void processEntityMetadata( XmlAnnotationHelper.applyRowId( jaxbEntity.getRowid(), classDetails, xmlDocumentContext ); + applyTenantId( classDetails, jaxbEntity, classAccessType, xmlDocumentContext ); + // todo : secondary-tables } + private static void applyTenantId( + MutableClassDetails classDetails, + JaxbEntityImpl jaxbEntity, + AccessType classAccessType, + XmlDocumentContext xmlDocumentContext) { + final JaxbTenantIdImpl jaxbTenantId = jaxbEntity.getTenantId(); + if ( jaxbTenantId != null ) { + final MutableMemberDetails memberDetails = XmlProcessingHelper.getAttributeMember( + jaxbTenantId.getName(), + coalesce( jaxbTenantId.getAccess(), classAccessType ), + classDetails + ); + XmlProcessingHelper.getOrMakeAnnotation( + TenantId.class, + memberDetails, + xmlDocumentContext + ); + BasicAttributeProcessing.processBasicAttribute( + jaxbTenantId, + classDetails, + classAccessType, + xmlDocumentContext + ); + } + } + private static void adjustNonDynamicTypeMember( MutableMemberDetails memberDetails, diff --git a/src/test/java/org/hibernate/models/orm/xml/dynamic/TenantIdTest.java b/src/test/java/org/hibernate/models/orm/xml/dynamic/TenantIdTest.java new file mode 100644 index 0000000..366c3b1 --- /dev/null +++ b/src/test/java/org/hibernate/models/orm/xml/dynamic/TenantIdTest.java @@ -0,0 +1,89 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.models.orm.xml.dynamic; + + + import java.util.Set; + + + import org.hibernate.annotations.TenantId; + import org.hibernate.boot.internal.BootstrapContextImpl; + import org.hibernate.boot.internal.MetadataBuilderImpl; + import org.hibernate.boot.model.process.spi.ManagedResources; + import org.hibernate.boot.models.categorize.spi.CategorizedDomainModel; + import org.hibernate.boot.models.categorize.spi.EntityHierarchy; + import org.hibernate.boot.models.categorize.spi.EntityTypeMetadata; + import org.hibernate.boot.registry.StandardServiceRegistry; + import org.hibernate.boot.registry.StandardServiceRegistryBuilder; + import org.hibernate.models.orm.process.ManagedResourcesImpl; + import org.hibernate.models.spi.AnnotationUsage; + import org.hibernate.models.spi.ClassDetails; + import org.hibernate.models.spi.FieldDetails; + + + import org.junit.jupiter.api.Test; + + + import jakarta.persistence.Basic; + import jakarta.persistence.Column; + import jakarta.persistence.FetchType; + + + import static org.assertj.core.api.Assertions.assertThat; + import static org.hibernate.boot.models.categorize.spi.ManagedResourcesProcessor.processManagedResources; + + +public class TenantIdTest { + @Test + void testSimpleDynamicModel() { + final ManagedResources managedResources = new ManagedResourcesImpl.Builder() + .addXmlMappings( "mappings/dynamic/dynamic-tenantid.xml" ) + .build(); + try (StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().build()) { + final BootstrapContextImpl bootstrapContext = new BootstrapContextImpl( + serviceRegistry, + new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ) + ); + final CategorizedDomainModel categorizedDomainModel = processManagedResources( + managedResources, + bootstrapContext + ); + + final Set entityHierarchies = categorizedDomainModel.getEntityHierarchies(); + assertThat( entityHierarchies ).hasSize( 2 ); + + entityHierarchies.forEach( + entityHierarchy -> { + final EntityTypeMetadata root = entityHierarchy.getRoot(); + final String entityName = root.getEntityName(); + + final FieldDetails field = root.getClassDetails().findFieldByName( "tenantId" ); + + if ( entityName.equals( "EntityWithoutTenantId" ) ) { + assertThat( field ).isNull(); + } + else { + final AnnotationUsage tenantIdAnnotationUsage = field.getAnnotationUsage( TenantId.class ); + + assertThat( tenantIdAnnotationUsage ).isNotNull(); + + final AnnotationUsage basicAnnotationUsage = field.getAnnotationUsage( Basic.class ); + assertThat( basicAnnotationUsage ).isNotNull(); + assertThat( basicAnnotationUsage.getAttributeValue( "fetch" ) ) + .isEqualTo( FetchType.EAGER ); + assertThat( basicAnnotationUsage.getBoolean( "optional" ) ).isTrue(); + + final AnnotationUsage columnAnnotationUsage = field.getAnnotationUsage( Column.class ); + assertThat( basicAnnotationUsage ).isNotNull(); + assertThat( columnAnnotationUsage.getString( "name" ) ).isEqualTo( "TENANT_ID" ); + assertThat( columnAnnotationUsage.getBoolean( "insertable" ) ).isFalse(); + } + } + ); + } + } +} diff --git a/src/test/resources/mappings/dynamic/dynamic-tenantid.xml b/src/test/resources/mappings/dynamic/dynamic-tenantid.xml new file mode 100644 index 0000000..ccc607f --- /dev/null +++ b/src/test/resources/mappings/dynamic/dynamic-tenantid.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + +