From f1fd58fa185fb1cfe0c84ec3623373483fc1b8d5 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Mon, 26 Aug 2024 16:15:59 +0200 Subject: [PATCH] HHH-17117 allow @TenantId to form part of composite key Signed-off-by: Gavin King --- .../org/hibernate/annotations/TenantId.java | 1 + .../InFlightMetadataCollectorImpl.java | 33 +---- .../internal/AbstractSaveEventListener.java | 1 - .../internal/TenantIdGeneration.java | 26 ++-- .../org/hibernate/internal/FilterImpl.java | 16 ++- .../internal/SessionFactoryImpl.java | 2 +- .../java/org/hibernate/mapping/Component.java | 54 ++++---- .../java/org/hibernate/mapping/KeyValue.java | 7 +- .../org/hibernate/mapping/SimpleValue.java | 10 +- .../AbstractCollectionPersister.java | 2 +- .../orm/test/tenantidpk/Account.java | 26 ++++ .../hibernate/orm/test/tenantidpk/Client.java | 38 ++++++ .../orm/test/tenantidpk/TenantPkTest.java | 123 ++++++++++++++++++ .../processor/util/xml/XmlParserHelper.java | 1 - 14 files changed, 255 insertions(+), 85 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/tenantidpk/Account.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/tenantidpk/Client.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/tenantidpk/TenantPkTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/TenantId.java b/hibernate-core/src/main/java/org/hibernate/annotations/TenantId.java index e3892d056c4f..98b01dc003f7 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/TenantId.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/TenantId.java @@ -26,6 +26,7 @@ * @author Gavin King */ @ValueGenerationType(generatedBy = TenantIdGeneration.class) +@IdGeneratorType(TenantIdGeneration.class) @AttributeBinderType(binder = TenantIdBinder.class) @Target({METHOD, FIELD}) @Retention(RUNTIME) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java index d6180d9ab8b4..d0a5f80fa1d3 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java @@ -1358,24 +1358,6 @@ else if ( clazz.hasDirectAnnotationUsage( Imported.class ) ) { } } - private static AnnotatedClassType getAnnotatedClassType2(ClassDetails classDetails) { - if ( classDetails.hasDirectAnnotationUsage( Entity.class ) ) { - return AnnotatedClassType.ENTITY; - } - else if ( classDetails.hasDirectAnnotationUsage( Embeddable.class ) ) { - return AnnotatedClassType.EMBEDDABLE; - } - else if ( classDetails.hasDirectAnnotationUsage( jakarta.persistence.MappedSuperclass.class ) ) { - return AnnotatedClassType.MAPPED_SUPERCLASS; - } - else if ( classDetails.hasDirectAnnotationUsage( Imported.class ) ) { - return AnnotatedClassType.IMPORTED; - } - else { - return AnnotatedClassType.NONE; - } - } - @Override public void addMappedSuperclass(Class type, MappedSuperclass mappedSuperclass) { if ( mappedSuperClasses == null ) { @@ -2022,10 +2004,10 @@ private void processEndOfQueue(List endOfQueueFkSecondPasses) { } } } - stopProcess = failingSecondPasses.size() == 0 || failingSecondPasses.size() == endOfQueueFkSecondPasses.size(); + stopProcess = failingSecondPasses.isEmpty() || failingSecondPasses.size() == endOfQueueFkSecondPasses.size(); endOfQueueFkSecondPasses = failingSecondPasses; } - if ( endOfQueueFkSecondPasses.size() > 0 ) { + if ( !endOfQueueFkSecondPasses.isEmpty() ) { throw originalException; } } @@ -2212,7 +2194,8 @@ private void processExportableProducers() { handleIdentifierValueBinding( entityBinding.getIdentifier(), dialect, - (RootClass) entityBinding + (RootClass) entityBinding, + entityBinding.getIdentifierProperty() ); } @@ -2225,22 +2208,20 @@ private void processExportableProducers() { handleIdentifierValueBinding( ( (IdentifierCollection) collection ).getIdentifier(), dialect, + null, null ); } } private void handleIdentifierValueBinding( - KeyValue identifierValueBinding, - Dialect dialect, - RootClass entityBinding) { + KeyValue identifierValueBinding, Dialect dialect, RootClass entityBinding, Property identifierProperty) { // todo : store this result (back into the entity or into the KeyValue, maybe?) // This process of instantiating the id-generator is called multiple times. // It was done this way in the old code too, so no "regression" here; but // it could be done better try { - final Generator generator = identifierValueBinding.createGenerator( dialect, entityBinding ); - + final Generator generator = identifierValueBinding.createGenerator( dialect, entityBinding, identifierProperty ); if ( generator instanceof ExportableProducer ) { ( (ExportableProducer) generator ).registerExportables( getDatabase() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java index b77ab7c2e96a..bb9f6aab7cf3 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java @@ -25,7 +25,6 @@ import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.Status; import org.hibernate.event.spi.EventSource; -import org.hibernate.id.Assigned; import org.hibernate.id.CompositeNestedGeneratedValueGenerator; import org.hibernate.id.IdentifierGenerationException; import org.hibernate.internal.CoreLogging; diff --git a/hibernate-core/src/main/java/org/hibernate/generator/internal/TenantIdGeneration.java b/hibernate-core/src/main/java/org/hibernate/generator/internal/TenantIdGeneration.java index 8b60131d9222..7feb4a05d932 100644 --- a/hibernate-core/src/main/java/org/hibernate/generator/internal/TenantIdGeneration.java +++ b/hibernate-core/src/main/java/org/hibernate/generator/internal/TenantIdGeneration.java @@ -51,24 +51,26 @@ public EnumSet getEventTypes() { @Override public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType) { final SessionFactoryImplementor sessionFactory = session.getSessionFactory(); - final JavaType tenantIdentifierJavaType = sessionFactory.getTenantIdentifierJavaType(); - final Object tenantId = session.getTenantIdentifierValue(); if ( currentValue != null ) { - final CurrentTenantIdentifierResolver resolver = sessionFactory.getCurrentTenantIdentifierResolver(); + final CurrentTenantIdentifierResolver resolver = + sessionFactory.getCurrentTenantIdentifierResolver(); if ( resolver != null && resolver.isRoot( tenantId ) ) { // the "root" tenant is allowed to set the tenant id explicitly return currentValue; } - if ( !tenantIdentifierJavaType.areEqual( currentValue, tenantId ) ) { - throw new PropertyValueException( - "assigned tenant id differs from current tenant id: " + - tenantIdentifierJavaType.toString( currentValue ) + - "!=" + - tenantIdentifierJavaType.toString( tenantId ), - entityName, - propertyName - ); + else { + final JavaType tenantIdJavaType = sessionFactory.getTenantIdentifierJavaType(); + if ( !tenantIdJavaType.areEqual( currentValue, tenantId ) ) { + throw new PropertyValueException( + "assigned tenant id differs from current tenant id [" + + tenantIdJavaType.toString( currentValue ) + + " != " + + tenantIdJavaType.toString( tenantId ) + "]", + entityName, + propertyName + ); + } } } return tenantId; diff --git a/hibernate-core/src/main/java/org/hibernate/internal/FilterImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/FilterImpl.java index 9505d0d5b583..d1b70555d564 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/FilterImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/FilterImpl.java @@ -103,15 +103,16 @@ public Map getParameters() { * of the passed value did not match the configured type. */ public Filter setParameter(String name, Object value) throws IllegalArgumentException { - Object argument = definition.processArgument(value); + final Object argument = definition.processArgument( value ); // Make sure this is a defined parameter and check the incoming value type - JdbcMapping type = definition.getParameterJdbcMapping( name ); + final JdbcMapping type = definition.getParameterJdbcMapping( name ); if ( type == null ) { - throw new IllegalArgumentException( "Undefined filter parameter [" + name + "]" ); + throw new IllegalArgumentException( "Undefined filter parameter '" + name + "'" ); } if ( argument != null && !type.getJavaTypeDescriptor().isInstance( argument ) ) { - throw new IllegalArgumentException( "Incorrect type for parameter [" + name + "]" ); + throw new IllegalArgumentException( "Argument assigned to filter parameter '" + name + + "' is not of type '" + type.getJavaTypeDescriptor().getTypeName() + "'" ); } if ( parameters == null ) { parameters = new TreeMap<>(); @@ -133,14 +134,15 @@ public Filter setParameterList(String name, Collection values) throws Hiberna if ( values == null ) { throw new IllegalArgumentException( "Collection must be not null" ); } - JdbcMapping type = definition.getParameterJdbcMapping( name ); + final JdbcMapping type = definition.getParameterJdbcMapping( name ); if ( type == null ) { - throw new HibernateException( "Undefined filter parameter [" + name + "]" ); + throw new HibernateException( "Undefined filter parameter '" + name + "'" ); } if ( !values.isEmpty() ) { final Object element = values.iterator().next(); if ( !type.getJavaTypeDescriptor().isInstance( element ) ) { - throw new HibernateException( "Incorrect type for parameter [" + name + "]" ); + throw new IllegalArgumentException( "Argument assigned to filter parameter '" + name + + "' is not of type '" + type.getJavaTypeDescriptor().getTypeName() + "'" ); } } if ( parameters == null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index 0ca466b07018..fb70eba506b1 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -457,7 +457,7 @@ private static Map createGenerators( for ( PersistentClass model : bootMetamodel.getEntityBindings() ) { if ( !model.isInherited() ) { final KeyValue id = model.getIdentifier(); - final Generator generator = id.createGenerator( dialect, (RootClass) model ); + final Generator generator = id.createGenerator( dialect, (RootClass) model, model.getIdentifierProperty() ); if ( generator instanceof Configurable ) { final Configurable identifierGenerator = (Configurable) generator; identifierGenerator.initialize( sqlStringGenerationContext ); diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Component.java b/hibernate-core/src/main/java/org/hibernate/mapping/Component.java index 5b3070deedf6..e434cf660dc8 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Component.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Component.java @@ -11,7 +11,6 @@ import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; @@ -546,10 +545,6 @@ public void setKey(boolean isKey) { this.isKey = isKey; } - public boolean hasPojoRepresentation() { - return componentClassName!=null; - } - /** * Returns the {@link Property} at the specified position in this {@link Component}. * @@ -661,37 +656,30 @@ public String toString() { } @Override - public Generator createGenerator(Dialect dialect, RootClass rootClass) throws MappingException { + public Generator createGenerator(Dialect dialect, RootClass rootClass, Property property) { if ( builtIdentifierGenerator == null ) { builtIdentifierGenerator = buildIdentifierGenerator( dialect, rootClass ); } return builtIdentifierGenerator; } - private Generator buildIdentifierGenerator( Dialect dialect, RootClass rootClass) throws MappingException { - if ( !getCustomIdGeneratorCreator().isAssigned() ) { - return super.createGenerator( dialect, rootClass ); - } - - final Class entityClass = rootClass.getMappedClass(); - final Class attributeDeclarer = getAttributeDeclarer( rootClass, entityClass ); - - final CompositeNestedGeneratedValueGenerator.GenerationContextLocator locator = - new StandardGenerationContextLocator( rootClass.getEntityName() ); + private Generator buildIdentifierGenerator(Dialect dialect, RootClass rootClass) { final CompositeNestedGeneratedValueGenerator generator = - new CompositeNestedGeneratedValueGenerator( locator, getType() ); - + new CompositeNestedGeneratedValueGenerator( + new StandardGenerationContextLocator( rootClass.getEntityName() ), + getType() + ); final List properties = getProperties(); for ( int i = 0; i < properties.size(); i++ ) { final Property property = properties.get( i ); if ( property.getValue().isSimpleValue() ) { final SimpleValue value = (SimpleValue) property.getValue(); if ( !value.getCustomIdGeneratorCreator().isAssigned() ) { - // skip any 'assigned' generators, they would have been handled by - // the StandardGenerationContextLocator + // skip any 'assigned' generators, they would have been + // handled by the StandardGenerationContextLocator generator.addGeneratedValuePlan( new ValueGenerationPlan( - value.createGenerator( dialect, rootClass ), - getType().isMutable() ? injector( property, attributeDeclarer ) : null, + value.createGenerator( dialect, rootClass, property ), + getType().isMutable() ? injector( property, getAttributeDeclarer( rootClass ) ) : null, i ) ); } @@ -700,23 +688,27 @@ private Generator buildIdentifierGenerator( Dialect dialect, RootClass rootClass return generator; } - private Class getAttributeDeclarer(RootClass rootClass, Class entityClass) { - final Class attributeDeclarer; // what class is the declarer of the composite pk attributes - // IMPL NOTE : See the javadoc discussion on CompositeNestedGeneratedValueGenerator wrt the - // various scenarios for which we need to account here + /** + * Return the class that declares the composite pk attributes, + * which might be an {@code @IdClass}, an {@code @EmbeddedId}, + * of the entity class itself. + */ + private Class getAttributeDeclarer(RootClass rootClass) { + // See the javadoc discussion on CompositeNestedGeneratedValueGenerator + // for the various scenarios we need to account for here if ( rootClass.getIdentifierMapper() != null ) { // we have the @IdClass / case - attributeDeclarer = resolveComponentClass(); + return resolveComponentClass(); } else if ( rootClass.getIdentifierProperty() != null ) { // we have the "@EmbeddedId" / case - attributeDeclarer = resolveComponentClass(); + return resolveComponentClass(); } else { - // we have the "straight up" embedded (again the Hibernate term) component identifier - attributeDeclarer = entityClass; + // we have the "straight up" embedded (again the Hibernate term) + // component identifier: the entity class itself is the id class + return rootClass.getMappedClass(); } - return attributeDeclarer; } private Setter injector(Property property, Class attributeDeclarer) { diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/KeyValue.java b/hibernate-core/src/main/java/org/hibernate/mapping/KeyValue.java index de8b3548c7a3..d225776082dc 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/KeyValue.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/KeyValue.java @@ -27,6 +27,11 @@ public interface KeyValue extends Value { boolean isUpdateable(); - Generator createGenerator(Dialect dialect, RootClass rootClass); + @Deprecated(since = "7.0") + default Generator createGenerator(Dialect dialect, RootClass rootClass) { + return createGenerator( dialect, rootClass, null ); + } + + Generator createGenerator(Dialect dialect, RootClass rootClass, Property property); } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java b/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java index eb7d0aa88076..706383ac9c5b 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java @@ -375,10 +375,10 @@ public GeneratorCreator getCustomIdGeneratorCreator() { } @Override - public Generator createGenerator(Dialect dialect, RootClass rootClass) { + public Generator createGenerator(Dialect dialect, RootClass rootClass, Property property) { if ( generator == null ) { if ( customIdGeneratorCreator != null ) { - generator = customIdGeneratorCreator.createGenerator( new IdGeneratorCreationContext( rootClass ) ); + generator = customIdGeneratorCreator.createGenerator( new IdGeneratorCreationContext( rootClass, property ) ); } } return generator; @@ -1011,9 +1011,11 @@ public Long[] getColumnLengths() { private class IdGeneratorCreationContext implements GeneratorCreationContext { private final RootClass rootClass; + private final Property property; - public IdGeneratorCreationContext(RootClass rootClass) { + public IdGeneratorCreationContext(RootClass rootClass, Property property) { this.rootClass = rootClass; + this.property = property; } @Override @@ -1048,7 +1050,7 @@ public PersistentClass getPersistentClass() { @Override public Property getProperty() { - return rootClass.getIdentifierProperty(); + return property; } // we could add these if it helps integrate old infrastructure diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java index 32b03ee31ffe..de38bf4023d3 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java @@ -598,7 +598,7 @@ else if ( indexedCollection instanceof org.hibernate.mapping.Map } private BeforeExecutionGenerator createGenerator(RuntimeModelCreationContext context, IdentifierCollection collection) { - final Generator generator = collection.getIdentifier().createGenerator( context.getDialect(), null ); + final Generator generator = collection.getIdentifier().createGenerator( context.getDialect(), null, null ); if ( generator.generatedOnExecution() ) { throw new MappingException("must be an BeforeExecutionGenerator"); //TODO fix message } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/tenantidpk/Account.java b/hibernate-core/src/test/java/org/hibernate/orm/test/tenantidpk/Account.java new file mode 100644 index 000000000000..b44182fe6865 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/tenantidpk/Account.java @@ -0,0 +1,26 @@ +package org.hibernate.orm.test.tenantidpk; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import org.hibernate.annotations.TenantId; + +import java.util.UUID; + +@Entity +public class Account { + + @Id @GeneratedValue Long id; + + @Id @TenantId UUID tenantId; + + @ManyToOne(optional = false) + Client client; + + public Account(Client client) { + this.client = client; + } + + Account() {} +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/tenantidpk/Client.java b/hibernate-core/src/test/java/org/hibernate/orm/test/tenantidpk/Client.java new file mode 100644 index 000000000000..926c3bee9c75 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/tenantidpk/Client.java @@ -0,0 +1,38 @@ +/* + * 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.orm.test.tenantidpk; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import org.hibernate.annotations.TenantId; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +@Entity +public class Client { + @Id + @GeneratedValue + Long id; + + String name; + + @Id @TenantId + UUID tenantId; + + @OneToMany(mappedBy = "client") + Set accounts = new HashSet<>(); + + public Client(String name) { + this.name = name; + } + + Client() {} +} \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/tenantidpk/TenantPkTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/tenantidpk/TenantPkTest.java new file mode 100644 index 000000000000..4879ecbb5551 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/tenantidpk/TenantPkTest.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.orm.test.tenantidpk; + +import org.hibernate.PropertyValueException; +import org.hibernate.binder.internal.TenantIdBinder; +import org.hibernate.boot.SessionFactoryBuilder; +import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.context.spi.CurrentTenantIdentifierResolver; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryProducer; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +import static org.hibernate.cfg.AvailableSettings.JAKARTA_HBM2DDL_DATABASE_ACTION; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.fail; + +@SessionFactory +@DomainModel(annotatedClasses = { Account.class, Client.class }) +@ServiceRegistry( + settings = { + @Setting(name = JAKARTA_HBM2DDL_DATABASE_ACTION, value = "create-drop") + } +) +public class TenantPkTest implements SessionFactoryProducer { + + private static final UUID mine = UUID.randomUUID(); + private static final UUID yours = UUID.randomUUID(); + + UUID currentTenant; + + @AfterEach + public void cleanup(SessionFactoryScope scope) { + scope.inTransaction( session -> { + session.createQuery("delete from Account").executeUpdate(); + session.createQuery("delete from Client").executeUpdate(); + }); + } + + @Override + public SessionFactoryImplementor produceSessionFactory(MetadataImplementor model) { + final SessionFactoryBuilder sessionFactoryBuilder = model.getSessionFactoryBuilder(); + sessionFactoryBuilder.applyCurrentTenantIdentifierResolver( new CurrentTenantIdentifierResolver() { + @Override + public UUID resolveCurrentTenantIdentifier() { + return currentTenant; + } + @Override + public boolean validateExistingCurrentSessions() { + return false; + } + } ); + return (SessionFactoryImplementor) sessionFactoryBuilder.build(); + } + + @Test + public void test(SessionFactoryScope scope) { + currentTenant = mine; + Client client = new Client("Gavin"); + Account acc = new Account(client); + scope.inTransaction( session -> { + session.persist(client); + session.persist(acc); + } ); + scope.inTransaction( session -> { + assertNotNull( session.createSelectionQuery("where id=?1 and tenantId=?2", Account.class) + .setParameter(1, acc.id) + .setParameter(2, mine) + .getSingleResultOrNull() ); + assertEquals( 1, session.createQuery("from Account").getResultList().size() ); + } ); + assertEquals(mine, acc.tenantId); + + currentTenant = yours; + scope.inTransaction( session -> { + assertNotNull( session.createSelectionQuery("where id=?1 and tenantId=?2", Account.class) + .setParameter(1, acc.id) + .setParameter(2, yours) + .getSingleResultOrNull() ); + assertEquals( 0, session.createQuery("from Account").getResultList().size() ); + session.disableFilter(TenantIdBinder.FILTER_NAME); + assertNotNull( session.createSelectionQuery("where id=?1 and tenantId=?2", Account.class) + .setParameter(1, acc.id) + .setParameter(2, yours) + .getSingleResultOrNull() ); + assertEquals( 1, session.createQuery("from Account").getResultList().size() ); + } ); + } + + @Test + public void testErrorOnInsert(SessionFactoryScope scope) { + currentTenant = mine; + Client client = new Client("Gavin"); + Account acc = new Account(client); + acc.tenantId = yours; + try { + scope.inTransaction( session -> { + session.persist(client); + session.persist(acc); + } ); + fail(); +// assertEquals( mine, acc.tenantId ); +// assertEquals( mine, client.tenantId ); + } + catch ( PropertyValueException e ) { + // expected + } + } +} diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/util/xml/XmlParserHelper.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/util/xml/XmlParserHelper.java index 18f7dcc7ce13..e0dceb9bc8e3 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/util/xml/XmlParserHelper.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/util/xml/XmlParserHelper.java @@ -9,7 +9,6 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; -import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import javax.tools.FileObject;