HHH-14191 - ANY mapping support

- `@ManyToAny`
- embeddable sub-attribute
This commit is contained in:
Steve Ebersole 2020-08-27 17:37:28 -05:00
parent 97a88ebbcf
commit 3d46fabeb5
39 changed files with 1024 additions and 545 deletions

View File

@ -6,12 +6,14 @@
*/
package org.hibernate;
import org.hibernate.metamodel.mapping.NonTransientException;
/**
* Thrown from methods added for 6.0 that are not yet implemented.
*
* todo (6.0) : prior going final, we need to find all usages of this and implement all methods (or throw a different exception)
*/
public class NotYetImplementedFor6Exception extends RuntimeException {
public class NotYetImplementedFor6Exception extends RuntimeException implements NonTransientException {
public NotYetImplementedFor6Exception(String message) {
super( message );
}

View File

@ -61,6 +61,7 @@ import org.hibernate.mapping.SyntheticProperty;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.ToOne;
import org.hibernate.mapping.Value;
import org.hibernate.type.DiscriminatorType;
import org.jboss.logging.Logger;
@ -953,46 +954,53 @@ public class BinderHelper {
EntityBinder entityBinder,
boolean optional,
MetadataBuildingContext context) {
final XProperty xProperty = inferredData.getProperty();
//All FK columns should be in the same table
Any value = new Any( context, columns[0].getTable() );
AnyMetaDef metaAnnDef = inferredData.getProperty().getAnnotation( AnyMetaDef.class );
final Any value = new Any( context, columns[0].getTable() );
value.setLazy( lazy );
if ( metaAnnDef != null ) {
//local has precedence over general and can be mapped for future reference if named
bindAnyMetaDefs( inferredData.getProperty(), context );
}
else {
metaAnnDef = context.getMetadataCollector().getAnyMetaDef( anyMetaDefName );
}
if ( metaAnnDef != null ) {
value.setIdentifierType( metaAnnDef.idType() );
value.setMetaType( metaAnnDef.metaType() );
HashMap values = new HashMap();
org.hibernate.type.Type metaType = context.getMetadataCollector().getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( value.getMetaType() );
for (MetaValue metaValue : metaAnnDef.metaValues()) {
try {
Object discrim = ( (org.hibernate.type.DiscriminatorType) metaType ).stringToObject( metaValue
.value() );
String entityName = metaValue.targetEntity().getName();
values.put( discrim, entityName );
}
catch (ClassCastException cce) {
throw new MappingException( "metaType was not a DiscriminatorType: "
+ metaType.getName() );
}
catch (Exception e) {
throw new MappingException( "could not interpret metaValue", e );
}
}
if ( !values.isEmpty() ) {
value.setMetaValues( values );
}
final AnyMetaDef metaDefToUse;
final AnyMetaDef localMetaDefAnn = xProperty.getAnnotation( AnyMetaDef.class );
if ( localMetaDefAnn != null ) {
//local has precedence over general and can be mapped for future reference if named
bindAnyMetaDefs(xProperty, context );
metaDefToUse = localMetaDefAnn;
}
else {
throw new AnnotationException( "Unable to find @AnyMetaDef for an @(ManyTo)Any mapping: "
+ StringHelper.qualify( propertyHolder.getPath(), inferredData.getPropertyName() ) );
metaDefToUse = context.getMetadataCollector().getAnyMetaDef( anyMetaDefName );
if ( metaDefToUse == null ) {
throw new AnnotationException(
"Unable to find @AnyMetaDef for an @(ManyTo)Any mapping: "
+ StringHelper.qualify( propertyHolder.getPath(), inferredData.getPropertyName() )
);
}
}
value.setIdentifierType( metaDefToUse.idType() );
value.setMetaType( metaDefToUse.metaType() );
final HashMap<Object,String> values = new HashMap<>();
final DiscriminatorType<?> metaType = (DiscriminatorType<?>) context.getMetadataCollector()
.getTypeConfiguration()
.getBasicTypeRegistry()
.getRegisteredType( value.getMetaType() );
for (int i = 0; i < metaDefToUse.metaValues().length; i++) {
final MetaValue metaValue = metaDefToUse.metaValues()[ i ];
try {
final Object discriminator = metaType.stringToObject( metaValue.value() );
final String entityName = metaValue.targetEntity().getName();
values.put( discriminator, entityName );
}
catch (Exception e) {
throw new MappingException( "Could not interpret @MetaValue", e );
}
}
if ( !values.isEmpty() ) {
value.setMetaValues( values );
}
value.setCascadeDeleteEnabled( cascadeOnDelete );

View File

@ -0,0 +1,27 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.internal.util;
/**
* @author Steve Ebersole
*/
public class JavaHelper {
public static Package getPackageFor(String name) {
return getPackageFor( name, JavaHelper.class.getClassLoader() );
}
public static Package getPackageFor(String name, ClassLoader classLoader) {
// after Java 9 we can do -
//return classLoader.getDefinedPackage( name );
return Package.getPackage( name );
}
private JavaHelper() {
// disallow direct instantiation
}
}

View File

@ -7,6 +7,7 @@
package org.hibernate.metamodel.mapping;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.FetchableContainer;
/**
* A discriminated association. This is similar to an association to
@ -20,9 +21,9 @@ import org.hibernate.sql.results.graph.Fetchable;
*
* @author Steve Ebersole
*/
public interface DiscriminatedAssociationModelPart extends Fetchable {
public interface DiscriminatedAssociationModelPart extends Fetchable, FetchableContainer {
BasicValuedModelPart getDiscriminatorPart();
ModelPart getKeyPart();
BasicValuedModelPart getKeyPart();
EntityMappingType resolveDiscriminatorValue(Object discriminatorValue);
}

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.metamodel.mapping;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -18,15 +19,19 @@ import java.util.function.Function;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.mapping.Any;
import org.hibernate.mapping.BasicValue;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Selectable;
import org.hibernate.metamodel.mapping.internal.DiscriminatedAssociationAttributeMapping;
import org.hibernate.metamodel.mapping.internal.MappingModelCreationHelper;
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
@ -34,6 +39,7 @@ import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.tree.from.TableGroup;
@ -41,12 +47,15 @@ import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableResultImpl;
import org.hibernate.type.AnyType;
import org.hibernate.type.BasicType;
import org.hibernate.type.CollectionType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.MutabilityPlan;
import org.hibernate.type.spi.TypeConfiguration;
/**
@ -154,8 +163,10 @@ public class EmbeddableMappingType implements ManagedMappingType {
Component bootDescriptor,
CompositeType compositeType,
MappingModelCreationProcess creationProcess) {
final String containingTableExpression = valueMapping.getContainingTableExpression();
final SessionFactoryImplementor sessionFactory = creationProcess.getCreationContext().getSessionFactory();
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
final String containingTableExpression = valueMapping.getContainingTableExpression();
final List<String> mappedColumnExpressions = valueMapping.getMappedColumnExpressions();
final Type[] subtypes = compositeType.getSubtypes();
@ -174,7 +185,7 @@ public class EmbeddableMappingType implements ManagedMappingType {
final Selectable selectable = basicValue.getColumn();
final String mappedColumnExpression = mappedColumnExpressions.get( columnPosition++ );
assert mappedColumnExpression.equals( selectable.getText( creationProcess.getCreationContext().getSessionFactory().getDialect() ) );
assert mappedColumnExpression.equals( selectable.getText( sessionFactory.getDialect() ) );
attributeMappings.put(
bootPropertyDescriptor.getName(),
@ -196,9 +207,112 @@ public class EmbeddableMappingType implements ManagedMappingType {
)
);
}
else if ( subtype instanceof AnyType ) {
final Any bootValueMapping = (Any) bootPropertyDescriptor.getValue();
final AnyType anyType = (AnyType) subtype;
final PropertyAccess propertyAccess = representationStrategy.resolvePropertyAccess( bootPropertyDescriptor );
final boolean nullable = bootValueMapping.isNullable();
final boolean insertable = bootPropertyDescriptor.isInsertable();
final boolean updateable = bootPropertyDescriptor.isUpdateable();
final boolean includeInOptimisticLocking = bootPropertyDescriptor.isOptimisticLocked();
final CascadeStyle cascadeStyle = compositeType.getCascadeStyle( attributeIndex );
final MutabilityPlan mutabilityPlan;
if ( updateable ) {
mutabilityPlan = new MutabilityPlan() {
@Override
public boolean isMutable() {
return true;
}
@Override
public Object deepCopy(Object value) {
if ( value == null ) {
return null;
}
return anyType.deepCopy( value, creationProcess.getCreationContext().getSessionFactory() );
}
@Override
public Serializable disassemble(Object value) {
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public Object assemble(Serializable cached) {
throw new NotYetImplementedFor6Exception( getClass() );
}
};
}
else {
mutabilityPlan = ImmutableMutabilityPlan.INSTANCE;
}
final StateArrayContributorMetadataAccess attributeMetadataAccess = entityMappingType -> new StateArrayContributorMetadata() {
@Override
public PropertyAccess getPropertyAccess() {
return propertyAccess;
}
@Override
public MutabilityPlan getMutabilityPlan() {
return mutabilityPlan;
}
@Override
public boolean isNullable() {
return nullable;
}
@Override
public boolean isInsertable() {
return insertable;
}
@Override
public boolean isUpdatable() {
return updateable;
}
@Override
public boolean isIncludedInDirtyChecking() {
// todo (6.0) : do not believe this is correct
return updateable;
}
@Override
public boolean isIncludedInOptimisticLocking() {
return includeInOptimisticLocking;
}
@Override
public CascadeStyle getCascadeStyle() {
return cascadeStyle;
}
};
attributeMappings.put(
bootPropertyDescriptor.getName(),
new DiscriminatedAssociationAttributeMapping(
valueMapping.getNavigableRole().append( bootPropertyDescriptor.getName() ),
typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Object.class ),
this,
attributeIndex,
attributeMetadataAccess,
bootPropertyDescriptor.isLazy() ? FetchTiming.DELAYED : FetchTiming.IMMEDIATE,
propertyAccess,
bootPropertyDescriptor,
anyType,
bootValueMapping,
creationProcess
)
);
}
else if ( subtype instanceof CompositeType ) {
final CompositeType subCompositeType = (CompositeType) subtype;
final int columnSpan = subCompositeType.getColumnSpan( creationProcess.getCreationContext().getSessionFactory() );
final int columnSpan = subCompositeType.getColumnSpan( sessionFactory );
final List<String> customReadExpressions = new ArrayList<>( columnSpan );
final List<String> customWriteExpressions = new ArrayList<>( columnSpan );

View File

@ -11,6 +11,7 @@ import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.sql.results.graph.FetchOptions;
/**
* @author Steve Ebersole
@ -25,7 +26,7 @@ public abstract class AbstractSingularAttributeMapping
String name,
int stateArrayPosition,
StateArrayContributorMetadataAccess attributeMetadataAccess,
FetchStrategy mappedFetchStrategy,
FetchOptions mappedFetchStrategy,
ManagedMappingType declaringType,
PropertyAccess propertyAccess) {
super( name, attributeMetadataAccess, mappedFetchStrategy, stateArrayPosition, declaringType );

View File

@ -6,7 +6,6 @@
*/
package org.hibernate.metamodel.mapping.internal;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.ManagedMappingType;
@ -44,7 +43,7 @@ public abstract class AbstractStateArrayContributorMapping
public AbstractStateArrayContributorMapping(
String name,
StateArrayContributorMetadataAccess attributeMetadataAccess,
FetchStrategy mappedFetchStrategy,
FetchOptions mappedFetchStrategy,
int stateArrayPosition,
ManagedMappingType declaringType) {
this(

View File

@ -42,25 +42,29 @@ import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnRefere
* @author Steve Ebersole
*/
public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions {
public static final String PART_NAME = EntityDiscriminatorMapping.ROLE_NAME;
public static final String ROLE_NAME = EntityDiscriminatorMapping.ROLE_NAME;
private final NavigableRole navigableRole;
private final DiscriminatedAssociationModelPart declaringType;
private final String table;
private final String column;
private final boolean nullable;
private final MetaType metaType;
public AnyDiscriminatorPart(
NavigableRole attributeRole,
NavigableRole partRole,
DiscriminatedAssociationModelPart declaringType,
String table,
String column,
boolean nullable,
MetaType metaType) {
this.navigableRole = attributeRole.append( PART_NAME );
this.navigableRole = partRole;
this.declaringType = declaringType;
this.table = table;
this.column = column;
this.nullable = nullable;
this.metaType = metaType;
}
@ -104,7 +108,7 @@ public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions
@Override
public String getPartName() {
return PART_NAME;
return ROLE_NAME;
}
@Override
@ -171,7 +175,7 @@ public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions
fetchParent,
fetchablePath,
this,
false,
nullable,
null,
fetchTiming,
creationState

View File

@ -39,14 +39,14 @@ import org.hibernate.sql.results.graph.basic.BasicFetch;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
import static org.hibernate.metamodel.mapping.internal.DiscriminatedAssociationMapping.KEY_ROLE_NAME;
/**
* Acts as a ModelPart for the key portion of an any-valued mapping
*
* @author Steve Ebersole
*/
public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
public static final String ROLE_NAME = "{key}";
private final NavigableRole navigableRole;
private final String table;
private final String column;
@ -56,9 +56,8 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
public AnyKeyPart(
NavigableRole navigableRole,
String table,
DiscriminatedAssociationModelPart anyPart, String table,
String column,
DiscriminatedAssociationModelPart anyPart,
boolean nullable,
JdbcMapping jdbcMapping) {
this.navigableRole = navigableRole;
@ -101,7 +100,7 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
@Override
public String getPartName() {
return KEY_ROLE_NAME;
return ROLE_NAME;
}
@Override
@ -126,7 +125,7 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
@Override
public FetchOptions getMappedFetchOptions() {
return null;
return this;
}
@Override
@ -149,7 +148,7 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
.getCreationContext()
.getSessionFactory();
final TableGroup tableGroup = fromClauseAccess.getTableGroup( fetchParent.getNavigablePath() );
final TableGroup tableGroup = fromClauseAccess.getTableGroup( fetchParent.getNavigablePath().getParent() );
final TableReference tableReference = tableGroup.getTableReference( table );
final Expression columnReference = sqlExpressionResolver.resolveSqlExpression(

View File

@ -6,17 +6,14 @@
*/
package org.hibernate.metamodel.mapping.internal;
import java.util.Iterator;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.mapping.Any;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Selectable;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.DiscriminatedAssociationModelPart;
import org.hibernate.metamodel.mapping.EntityMappingType;
@ -32,14 +29,8 @@ import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.type.AnyType;
import org.hibernate.type.BasicType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.MetaType;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import static org.hibernate.metamodel.mapping.internal.DiscriminatedAssociationMapping.KEY_ROLE_NAME;
/**
* Singular, any-valued attribute
*
@ -55,71 +46,35 @@ public class DiscriminatedAssociationAttributeMapping
public DiscriminatedAssociationAttributeMapping(
NavigableRole attributeRole,
JavaTypeDescriptor<Object> baseAssociationJtd,
JavaTypeDescriptor<?> baseAssociationJtd,
ManagedMappingType declaringType,
int stateArrayPosition,
StateArrayContributorMetadataAccess attributeMetadataAccess,
FetchStrategy mappedFetchStrategy,
FetchTiming fetchTiming,
PropertyAccess propertyAccess,
Property bootProperty,
AnyType anyType,
Any bootValueMapping,
MappingModelCreationProcess creationProcess) {
super( bootProperty.getName(), stateArrayPosition, attributeMetadataAccess, mappedFetchStrategy, declaringType, propertyAccess );
super(
bootProperty.getName(),
stateArrayPosition,
attributeMetadataAccess,
fetchTiming == FetchTiming.IMMEDIATE
? new FetchStrategy( FetchTiming.IMMEDIATE, FetchStyle.SELECT )
: new FetchStrategy( FetchTiming.DELAYED, FetchStyle.SELECT ),
declaringType,
propertyAccess
);
this.navigableRole = attributeRole;
final SessionFactoryImplementor sessionFactory = creationProcess.getCreationContext().getSessionFactory();
final JdbcEnvironment jdbcEnvironment = sessionFactory.getJdbcServices().getJdbcEnvironment();
final String tableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format(
bootValueMapping.getTable().getQualifiedTableName(),
jdbcEnvironment.getDialect()
);
assert bootValueMapping.getColumnSpan() > 1;
final Iterator<Selectable> columnIterator = bootValueMapping.getColumnIterator();
assert columnIterator.hasNext();
final AnyDiscriminatorPart discriminatorPart = new AnyDiscriminatorPart(
this.discriminatorMapping = DiscriminatedAssociationMapping.from(
attributeRole,
this,
tableName,
columnIterator.next().getText( jdbcEnvironment.getDialect() ),
(MetaType) anyType.getDiscriminatorType()
);
final Fetchable keyPart;
final Type keyType = anyType.getIdentifierType();
if ( keyType instanceof BasicType ) {
assert columnIterator.hasNext();
keyPart = new AnyKeyPart(
attributeRole.append( KEY_ROLE_NAME ),
tableName,
columnIterator.next().getText( jdbcEnvironment.getDialect() ),
this,
attributeMetadataAccess.resolveAttributeMetadata( null ).isNullable(),
(BasicType<?>) keyType
);
assert ! columnIterator.hasNext();
}
else {
assert keyType instanceof CompositeType;
throw new NotYetImplementedFor6Exception( getClass() );
}
this.discriminatorMapping = new DiscriminatedAssociationMapping(
this,
discriminatorPart,
keyPart,
baseAssociationJtd,
bootProperty.isLazy()
? FetchTiming.DELAYED
: FetchTiming.IMMEDIATE,
sessionFactory
this,
anyType,
bootValueMapping,
creationProcess
);
}
@ -129,7 +84,7 @@ public class DiscriminatedAssociationAttributeMapping
}
@Override
public ModelPart getKeyPart() {
public BasicValuedModelPart getKeyPart() {
return discriminatorMapping.getKeyPart();
}
@ -167,4 +122,34 @@ public class DiscriminatedAssociationAttributeMapping
public MappingType getMappedType() {
return discriminatorMapping;
}
@Override
public int getNumberOfFetchables() {
return 2;
}
@Override
public void visitFetchables(Consumer<Fetchable> fetchableConsumer, EntityMappingType treatTargetType) {
fetchableConsumer.accept( getDiscriminatorPart() );
fetchableConsumer.accept( getKeyPart() );
}
@Override
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
if ( AnyDiscriminatorPart.ROLE_NAME.equals( name ) ) {
return getDiscriminatorPart();
}
if ( AnyKeyPart.ROLE_NAME.equals( name ) ) {
return getKeyPart();
}
return null;
}
@Override
public void visitSubParts(Consumer<ModelPart> consumer, EntityMappingType treatTargetType) {
consumer.accept( getDiscriminatorPart() );
consumer.accept( getKeyPart() );
}
}

View File

@ -6,24 +6,33 @@
*/
package org.hibernate.metamodel.mapping.internal;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.mapping.Any;
import org.hibernate.mapping.Selectable;
import org.hibernate.metamodel.RuntimeMetamodels;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.DiscriminatedAssociationModelPart;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.graph.AssemblerCreationState;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.DomainResultGraphNode;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchOptions;
import org.hibernate.sql.results.graph.FetchParent;
@ -31,6 +40,9 @@ import org.hibernate.sql.results.graph.FetchParentAccess;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
import org.hibernate.type.AnyType;
import org.hibernate.type.BasicType;
import org.hibernate.type.MetaType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
@ -39,11 +51,67 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
* @author Steve Ebersole
*/
public class DiscriminatedAssociationMapping implements MappingType, FetchOptions {
public static final String KEY_ROLE_NAME = "{key}";
public static DiscriminatedAssociationMapping from(
NavigableRole containerRole,
JavaTypeDescriptor<?> baseAssociationJtd,
DiscriminatedAssociationModelPart declaringModelPart,
AnyType anyType,
Any bootValueMapping,
MappingModelCreationProcess creationProcess) {
final SessionFactoryImplementor sessionFactory = creationProcess.getCreationContext().getSessionFactory();
final JdbcEnvironment jdbcEnvironment = sessionFactory.getJdbcServices().getJdbcEnvironment();
final String tableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format(
bootValueMapping.getTable().getQualifiedTableName(),
jdbcEnvironment.getDialect()
);
assert bootValueMapping.getColumnSpan() == 2;
final Iterator<Selectable> columnIterator = bootValueMapping.getColumnIterator();
assert columnIterator.hasNext();
final Selectable metaColumn = columnIterator.next();
assert columnIterator.hasNext();
final Selectable keyColumn = columnIterator.next();
assert ! columnIterator.hasNext();
final AnyDiscriminatorPart discriminatorPart = new AnyDiscriminatorPart(
containerRole.append( AnyDiscriminatorPart.ROLE_NAME),
declaringModelPart,
tableName,
metaColumn.getText( jdbcEnvironment.getDialect() ),
bootValueMapping.isNullable(),
(MetaType) anyType.getDiscriminatorType()
);
final BasicType<?> keyType = (BasicType<?>) anyType.getIdentifierType();
final BasicValuedModelPart keyPart = new AnyKeyPart(
containerRole.append( AnyKeyPart.ROLE_NAME),
declaringModelPart,
tableName,
keyColumn.getText( jdbcEnvironment.getDialect() ),
bootValueMapping.isNullable(),
keyType
);
return new DiscriminatedAssociationMapping(
declaringModelPart,
discriminatorPart,
keyPart,
baseAssociationJtd,
bootValueMapping.isLazy()
? FetchTiming.DELAYED
: FetchTiming.IMMEDIATE,
bootValueMapping.getMetaValues(),
sessionFactory
);
}
private final DiscriminatedAssociationModelPart modelPart;
private final AnyDiscriminatorPart discriminatorPart;
private final Fetchable keyPart;
private final BasicValuedModelPart keyPart;
private final JavaTypeDescriptor<?> baseAssociationJtd;
@ -64,9 +132,10 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
public DiscriminatedAssociationMapping(
DiscriminatedAssociationModelPart modelPart,
AnyDiscriminatorPart discriminatorPart,
Fetchable keyPart,
BasicValuedModelPart keyPart,
JavaTypeDescriptor<?> baseAssociationJtd,
FetchTiming fetchTiming,
Map<Object,String> discriminatorValueMappings,
SessionFactoryImplementor sessionFactory) {
this.modelPart = modelPart;
this.discriminatorPart = discriminatorPart;
@ -75,8 +144,8 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
this.fetchTiming = fetchTiming;
final RuntimeMetamodels runtimeMetamodels = sessionFactory.getRuntimeMetamodels();
discriminatorPart.getMetaType().getDiscriminatorValuesToEntityNameMap().forEach(
(value, entityName) -> discriminatorValueMappings.add(
discriminatorValueMappings.forEach(
(value, entityName) -> this.discriminatorValueMappings.add(
new ValueMapping( value, runtimeMetamodels.getEntityMappingType( entityName ) )
)
);
@ -90,7 +159,7 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
return discriminatorPart;
}
public Fetchable getKeyPart() {
public BasicValuedModelPart getKeyPart() {
return keyPart;
}
@ -137,64 +206,65 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
LockMode lockMode,
String resultVariable,
DomainResultCreationState creationState) {
final Fetch discriminatorValueFetch = getDiscriminatorPart().generateFetch(
fetchParent,
fetchablePath.append( AnyDiscriminatorPart.PART_NAME ),
FetchTiming.IMMEDIATE,
selected,
lockMode,
resultVariable,
creationState
);
final Fetch keyValueFetch = getKeyPart().generateFetch(
fetchParent,
fetchablePath.append( ForeignKeyDescriptor.PART_NAME ),
FetchTiming.IMMEDIATE,
selected,
lockMode,
resultVariable,
creationState
);
return new AnyValuedFetch(
fetchablePath,
baseAssociationJtd,
modelPart,
discriminatorValueFetch,
keyValueFetch,
fetchTiming,
fetchParent
fetchParent,
creationState
);
}
private static class AnyValuedFetch implements Fetch {
public <T> DomainResult<T> createDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
String resultVariable,
DomainResultCreationState creationState) {
return new AnyValuedResult<>(
navigablePath,
baseAssociationJtd,
modelPart,
resultVariable
);
}
private static abstract class AnyValuedResultGraphNode implements DomainResultGraphNode, FetchParent {
private final NavigablePath navigablePath;
private final DiscriminatedAssociationModelPart fetchedPart;
private final DiscriminatedAssociationModelPart graphedPart;
private final JavaTypeDescriptor<?> baseAssociationJtd;
private final Fetch discriminatorValueFetch;
private final Fetch keyValueFetch;
private final FetchTiming fetchTiming;
private final FetchParent fetchParent;
private Fetch discriminatorValueFetch;
private Fetch keyValueFetch;
public AnyValuedFetch(
public AnyValuedResultGraphNode(
NavigablePath navigablePath,
DiscriminatedAssociationModelPart fetchedPart,
Fetch discriminatorValueFetch,
Fetch keyValueFetch,
FetchTiming fetchTiming,
FetchParent fetchParent) {
DiscriminatedAssociationModelPart graphedPart,
JavaTypeDescriptor<?> baseAssociationJtd) {
this.navigablePath = navigablePath;
this.fetchedPart = fetchedPart;
this.discriminatorValueFetch = discriminatorValueFetch;
this.keyValueFetch = keyValueFetch;
this.fetchTiming = fetchTiming;
this.fetchParent = fetchParent;
this.graphedPart = graphedPart;
this.baseAssociationJtd = baseAssociationJtd;
}
@Override
public JavaTypeDescriptor<?> getResultJavaTypeDescriptor() {
return fetchedPart.getJavaTypeDescriptor();
protected void afterInitialize(DomainResultCreationState creationState) {
final List<Fetch> fetches = creationState.visitFetches( this );
assert fetches.size() == 2;
discriminatorValueFetch = fetches.get( 0 );
keyValueFetch = fetches.get( 1 );
}
public Fetch getDiscriminatorValueFetch() {
return discriminatorValueFetch;
}
public Fetch getKeyValueFetch() {
return keyValueFetch;
}
public JavaTypeDescriptor<?> getBaseAssociationJtd() {
return baseAssociationJtd;
}
@Override
@ -202,6 +272,95 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
return navigablePath;
}
@Override
public JavaTypeDescriptor<?> getResultJavaTypeDescriptor() {
return baseAssociationJtd;
}
@Override
public boolean containsAnyNonScalarResults() {
return true;
}
@Override
public DiscriminatedAssociationModelPart getReferencedMappingContainer() {
return graphedPart;
}
@Override
public DiscriminatedAssociationModelPart getReferencedMappingType() {
return graphedPart;
}
@Override
public List<Fetch> getFetches() {
return Arrays.asList( discriminatorValueFetch, keyValueFetch );
}
@Override
public Fetch findFetch(Fetchable fetchable) {
assert graphedPart.getDiscriminatorPart() == fetchable
|| graphedPart.getKeyPart() == fetchable;
if ( graphedPart.getDiscriminatorPart() == fetchable ) {
return discriminatorValueFetch;
}
if ( graphedPart.getKeyPart() == fetchable ) {
return keyValueFetch;
}
throw new IllegalArgumentException( "Given Fetchable [" + fetchable + "] did not match either discriminator nor key mapping" );
}
}
private static class AnyValuedResult<T> extends AnyValuedResultGraphNode implements DomainResult<T> {
private final String resultVariable;
public AnyValuedResult(
NavigablePath navigablePath,
JavaTypeDescriptor<?> baseAssociationJtd,
DiscriminatedAssociationModelPart fetchedPart,
String resultVariable) {
super( navigablePath, fetchedPart, baseAssociationJtd );
this.resultVariable = resultVariable;
}
@Override
public String getResultVariable() {
return resultVariable;
}
@Override
public DomainResultAssembler<T> createResultAssembler(AssemblerCreationState creationState) {
return new AnyResultAssembler<>(
getNavigablePath(),
getReferencedMappingContainer(),
true,
getDiscriminatorValueFetch().createAssembler( null, creationState ),
getKeyValueFetch().createAssembler( null, creationState )
);
}
}
private static class AnyValuedFetch extends AnyValuedResultGraphNode implements Fetch {
private final FetchTiming fetchTiming;
private final FetchParent fetchParent;
public AnyValuedFetch(
NavigablePath navigablePath,
JavaTypeDescriptor<?> baseAssociationJtd,
DiscriminatedAssociationModelPart fetchedPart,
FetchTiming fetchTiming,
FetchParent fetchParent,
DomainResultCreationState creationState) {
super( navigablePath, fetchedPart, baseAssociationJtd );
this.fetchTiming = fetchTiming;
this.fetchParent = fetchParent;
afterInitialize( creationState );
}
@Override
public FetchParent getFetchParent() {
return fetchParent;
@ -209,7 +368,7 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
@Override
public DiscriminatedAssociationModelPart getFetchedMapping() {
return fetchedPart;
return getReferencedMappingContainer();
}
@Override
@ -231,21 +390,22 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
public DomainResultAssembler<?> createAssembler(
FetchParentAccess parentAccess,
AssemblerCreationState creationState) {
return new AnyResultAssembler(
navigablePath,
fetchedPart,
fetchTiming,
discriminatorValueFetch.createAssembler( parentAccess, creationState ),
keyValueFetch.createAssembler( parentAccess, creationState )
return new AnyResultAssembler<>(
getNavigablePath(),
getFetchedMapping(),
fetchTiming == FetchTiming.IMMEDIATE,
getDiscriminatorValueFetch().createAssembler( parentAccess, creationState ),
getKeyValueFetch().createAssembler( parentAccess, creationState )
);
}
}
private static class AnyResultAssembler implements DomainResultAssembler<Object> {
private static class AnyResultAssembler<T> implements DomainResultAssembler<T> {
private final NavigablePath fetchedPath;
private final DiscriminatedAssociationModelPart fetchedPart;
private final FetchTiming fetchTiming;
private final boolean eager;
private final DomainResultAssembler<?> discriminatorValueAssembler;
private final DomainResultAssembler<?> keyValueAssembler;
@ -253,18 +413,18 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
public AnyResultAssembler(
NavigablePath fetchedPath,
DiscriminatedAssociationModelPart fetchedPart,
FetchTiming fetchTiming,
boolean eager,
DomainResultAssembler<?> discriminatorValueAssembler,
DomainResultAssembler<?> keyValueAssembler) {
this.fetchedPath = fetchedPath;
this.fetchedPart = fetchedPart;
this.fetchTiming = fetchTiming;
this.eager = eager;
this.discriminatorValueAssembler = discriminatorValueAssembler;
this.keyValueAssembler = keyValueAssembler;
}
@Override
public Object assemble(
public T assemble(
RowProcessingState rowProcessingState,
JdbcValuesSourceProcessingOptions options) {
final Object discriminatorValue = discriminatorValueAssembler.assemble( rowProcessingState, options );
@ -283,17 +443,18 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
.getJdbcValuesSourceProcessingState()
.getSession();
return session.internalLoad(
//noinspection unchecked
return (T) session.internalLoad(
entityMapping.getEntityName(),
keyValue,
fetchTiming != FetchTiming.DELAYED,
eager,
// should not be null since we checked already. null would indicate bad data (ala, not-found handling)
false
);
}
@Override
public JavaTypeDescriptor<Object> getAssembledJavaTypeDescriptor() {
public JavaTypeDescriptor<T> getAssembledJavaTypeDescriptor() {
//noinspection unchecked
return fetchedPart.getJavaTypeDescriptor();
}

View File

@ -0,0 +1,167 @@
/*
* 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.metamodel.mapping.internal;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchTiming;
import org.hibernate.mapping.Any;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.DiscriminatedAssociationModelPart;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchOptions;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.type.AnyType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Steve Ebersole
*/
public class DiscriminatedCollectionPart implements DiscriminatedAssociationModelPart, CollectionPart {
private final Nature nature;
private final NavigableRole partRole;
private final DiscriminatedAssociationMapping discriminatorMapping;
public DiscriminatedCollectionPart(
Nature nature,
NavigableRole collectionRole,
JavaTypeDescriptor<Object> baseAssociationJtd,
Any bootValueMapping,
AnyType anyType,
MappingModelCreationProcess creationProcess) {
this.nature = nature;
this.partRole = collectionRole.append( nature.getName() );
this.discriminatorMapping = DiscriminatedAssociationMapping.from(
partRole,
baseAssociationJtd,
this,
anyType,
bootValueMapping,
creationProcess
);
}
@Override
public Nature getNature() {
return nature;
}
@Override
public BasicValuedModelPart getDiscriminatorPart() {
return discriminatorMapping.getDiscriminatorPart();
}
@Override
public BasicValuedModelPart getKeyPart() {
return discriminatorMapping.getKeyPart();
}
@Override
public EntityMappingType resolveDiscriminatorValue(Object discriminatorValue) {
return discriminatorMapping.resolveDiscriminatorValueToEntityName( discriminatorValue );
}
@Override
public String getFetchableName() {
return nature.getName();
}
@Override
public FetchOptions getMappedFetchOptions() {
return discriminatorMapping;
}
@Override
public Fetch generateFetch(
FetchParent fetchParent,
NavigablePath fetchablePath,
FetchTiming fetchTiming,
boolean selected,
LockMode lockMode,
String resultVariable,
DomainResultCreationState creationState) {
return discriminatorMapping.generateFetch(
fetchParent,
fetchablePath,
fetchTiming,
selected,
lockMode,
resultVariable,
creationState
);
}
@Override
public <T> DomainResult<T> createDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
String resultVariable,
DomainResultCreationState creationState) {
return discriminatorMapping.createDomainResult(
navigablePath,
tableGroup,
resultVariable,
creationState
);
}
@Override
public MappingType getPartMappingType() {
return discriminatorMapping;
}
@Override
public JavaTypeDescriptor<?> getJavaTypeDescriptor() {
return discriminatorMapping.getJavaTypeDescriptor();
}
@Override
public NavigableRole getNavigableRole() {
return partRole;
}
@Override
public EntityMappingType findContainingEntityMapping() {
return discriminatorMapping.getModelPart().findContainingEntityMapping();
}
@Override
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
if ( AnyDiscriminatorPart.ROLE_NAME.equals( name ) ) {
return getDiscriminatorPart();
}
if ( AnyKeyPart.ROLE_NAME.equals( name ) ) {
return getKeyPart();
}
return null;
}
@Override
public void visitSubParts(Consumer<ModelPart> consumer, EntityMappingType treatTargetType) {
consumer.accept( getDiscriminatorPart() );
consumer.accept( getKeyPart() );
}
@Override
public int getNumberOfFetchables() {
return 2;
}
}

View File

@ -33,6 +33,7 @@ import org.hibernate.engine.spi.CascadeStyles;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.mapping.Any;
import org.hibernate.mapping.BasicValue;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Component;
@ -90,6 +91,7 @@ import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.MutabilityPlan;
import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry;
import org.hibernate.type.spi.TypeConfiguration;
/**
* @author Steve Ebersole
@ -1261,6 +1263,24 @@ public class MappingModelCreationHelper {
return (CollectionPart) mappingType.getEmbeddedValueMapping();
}
if ( element instanceof Any ) {
final Any anyBootMapping = (Any) element;
final SessionFactoryImplementor sessionFactory = creationProcess.getCreationContext().getSessionFactory();
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
final JavaTypeDescriptorRegistry jtdRegistry = typeConfiguration.getJavaTypeDescriptorRegistry();
final JavaTypeDescriptor<Object> baseJtd = jtdRegistry.getDescriptor(Object.class);
return new DiscriminatedCollectionPart(
CollectionPart.Nature.ELEMENT,
collectionDescriptor.getNavigableRole(),
baseJtd,
anyBootMapping,
anyBootMapping.getType(),
creationProcess
);
}
if ( element instanceof OneToMany || element instanceof ToOne ) {
final EntityType elementEntityType = (EntityType) collectionDescriptor.getElementType();
final EntityPersister associatedEntity = creationProcess.getEntityPersister( elementEntityType.getAssociatedEntityName() );

View File

@ -10,6 +10,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.metamodel.mapping.MappingModelCreationLogger;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.NonTransientException;

View File

@ -6290,9 +6290,7 @@ public abstract class AbstractEntityPersister
return optimisticallyLocked;
}
},
bootProperty.isLazy()
? new FetchStrategy( FetchTiming.DELAYED, FetchStyle.SELECT )
: new FetchStrategy( FetchTiming.IMMEDIATE, FetchStyle.SELECT ),
bootProperty.isLazy() ? FetchTiming.DELAYED : FetchTiming.IMMEDIATE,
propertyAccess,
bootProperty,
(AnyType) attrType,
@ -6348,7 +6346,7 @@ public abstract class AbstractEntityPersister
}
@Override
public JavaTypeDescriptor getMappedJavaTypeDescriptor() {
public JavaTypeDescriptor<?> getMappedJavaTypeDescriptor() {
return javaTypeDescriptor;
}

View File

@ -0,0 +1,234 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.any.annotations;
import org.hibernate.LazyInitializationException;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@DomainModel(
annotatedPackageNames = "org.hibernate.orm.test.any.annotations",
annotatedClasses = {
StringProperty.class,
IntegerProperty.class,
LongProperty.class,
PropertySet.class,
LazyPropertySet.class,
PropertyMap.class,
PropertyList.class,
CharProperty.class
}
)
@SessionFactory
public class AnyTest {
@BeforeEach
public void createTestData(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
{
final PropertySet set1 = new PropertySet("string");
final Property property = new StringProperty("name", "Alex");
set1.setSomeProperty(property);
set1.addGeneralProperty(property);
session.save(set1);
final PropertySet set2 = new PropertySet("integer");
final Property property2 = new IntegerProperty("age", 33);
set2.setSomeProperty(property2);
set2.addGeneralProperty(property2);
session.save(set2);
}
{
final PropertyMap map = new PropertyMap("sample");
map.getProperties().put("name", new StringProperty("name", "Alex"));
map.getProperties().put("age", new IntegerProperty("age", 33));
session.save(map);
}
{
final PropertyList list = new PropertyList("sample");
final StringProperty stringProperty = new StringProperty("name", "Alex");
final IntegerProperty integerProperty = new IntegerProperty("age", 33);
final LongProperty longProperty = new LongProperty("distance", 121L);
final CharProperty charProp = new CharProperty("Est", 'E');
list.setSomeProperty(longProperty);
list.addGeneralProperty(stringProperty);
list.addGeneralProperty(integerProperty);
list.addGeneralProperty(longProperty);
list.addGeneralProperty(charProp);
session.save(list);
}
{
final LazyPropertySet set = new LazyPropertySet( "string" );
final Property property = new StringProperty( "name", "Alex" );
set.setSomeProperty( property );
session.save( set );
}
}
);
}
@AfterEach
public void dropTestData(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.createQuery( "delete StringProperty" ).executeUpdate();
session.createQuery( "delete IntegerProperty" ).executeUpdate();
session.createQuery( "delete LongProperty" ).executeUpdate();
session.createQuery( "delete CharProperty" ).executeUpdate();
session.createQuery( "delete PropertyList" ).executeUpdate();
session.createQuery( "delete PropertyMap" ).executeUpdate();
session.createQuery( "delete PropertySet" ).executeUpdate();
}
);
}
@Test
public void testDefaultAnyAssociation(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final QueryImplementor<PropertySet> query = session.createQuery("select s from PropertySet s where name = :name", PropertySet.class);
{
final PropertySet result = query.setParameter( "name", "string" ).uniqueResult();
assertNotNull( result );
assertNotNull( result.getSomeProperty() );
assertTrue( result.getSomeProperty() instanceof StringProperty );
assertEquals( "Alex", result.getSomeProperty().asString() );
assertNotNull( result.getGeneralProperties() );
assertEquals( 1, result.getGeneralProperties().size() );
assertEquals( "Alex", result.getGeneralProperties().get( 0 ).asString() );
}
{
final PropertySet result = query.setParameter( "name", "integer" ).uniqueResult();
assertNotNull( result );
assertNotNull( result.getSomeProperty() );
assertTrue( result.getSomeProperty() instanceof IntegerProperty );
assertEquals( "33", result.getSomeProperty().asString() );
assertNotNull( result.getGeneralProperties() );
assertEquals( 1, result.getGeneralProperties().size() );
assertEquals( "33", result.getGeneralProperties().get( 0 ).asString() );
}
}
);
}
@Test
public void testManyToAnyWithMap(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final PropertyMap actualMap = session
.createQuery( "SELECT m FROM PropertyMap m WHERE m.name = :name", PropertyMap.class )
.setParameter( "name", "sample" )
.uniqueResult();
assertNotNull( actualMap );
assertNotNull( actualMap.getProperties() );
Property property = actualMap.getProperties().get( "name" );
assertNotNull( property );
assertTrue( property instanceof StringProperty );
assertEquals( "Alex", property.asString() );
property = actualMap.getProperties().get( "age" );
assertNotNull( property );
assertTrue( property instanceof IntegerProperty );
assertEquals( "33", property.asString() );
}
);
}
@Test
public void testMetaDataUseWithManyToAny(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
//noinspection unchecked
final PropertyList<Property> actualList = session
.createQuery( "SELECT l FROM PropertyList l WHERE l.name = :name", PropertyList.class )
.setParameter( "name", "sample" )
.uniqueResult();
assertNotNull( actualList );
assertNotNull( actualList.getGeneralProperties() );
assertEquals( 4, actualList.getGeneralProperties().size() );
Property property = actualList.getSomeProperty();
assertNotNull( property );
assertTrue( property instanceof LongProperty );
assertEquals( "121", property.asString() );
assertEquals( "Alex", actualList.getGeneralProperties().get( 0 )
.asString() );
assertEquals( "33", actualList.getGeneralProperties().get( 1 ).asString() );
assertEquals( "121", actualList.getGeneralProperties().get( 2 ).asString() );
assertEquals( "E", actualList.getGeneralProperties().get( 3 ).asString() );
}
);
}
@Test
public void testFetchEager(SessionFactoryScope scope) {
final PropertySet result = scope.fromTransaction(
session -> {
final PropertySet localResult = session.createQuery("select s from PropertySet s where name = :name", PropertySet.class)
.setParameter("name", "string")
.getSingleResult();
assertNotNull( localResult );
assertNotNull( localResult.getSomeProperty() );
return localResult;
}
);
assertTrue( result.getSomeProperty() instanceof StringProperty );
assertEquals( "Alex", result.getSomeProperty().asString() );
}
@Test
public void testFetchLazy(SessionFactoryScope scope) {
final LazyPropertySet result = scope.fromTransaction(
session -> {
final LazyPropertySet localResult = session.createQuery("select s from LazyPropertySet s where name = :name", LazyPropertySet.class)
.setParameter("name", "string")
.getSingleResult();
assertNotNull( localResult );
assertNotNull( localResult.getSomeProperty() );
return localResult;
}
);
try {
result.getSomeProperty().asString();
fail( "should not get the property string after session closed." );
}
catch (LazyInitializationException e) {
// expected
}
catch (Exception e) {
fail( "should not throw exception other than LazyInitializationException." );
}
}
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.test.annotations.any;
package org.hibernate.orm.test.any.annotations;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

View File

@ -1,14 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.test.annotations.any;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
package org.hibernate.orm.test.any.annotations;
import javax.persistence.Column;
import javax.persistence.Embeddable;
@ -21,67 +17,63 @@ import javax.persistence.Table;
import org.hibernate.annotations.Any;
import org.hibernate.annotations.AnyMetaDef;
import org.hibernate.annotations.MetaValue;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.junit.Test;
public class EmbeddedAnyTest extends BaseEntityManagerFunctionalTestCase {
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[]{ Foo.class, Bar1.class, Bar2.class };
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@DomainModel( annotatedClasses = { EmbeddedAnyTest.Foo.class, EmbeddedAnyTest.Bar1.class, EmbeddedAnyTest.Bar2.class } )
@SessionFactory
public class EmbeddedAnyTest {
@BeforeEach
public void createTestData(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final Foo foo1 = new Foo();
foo1.setId( 1 );
final Bar1 bar1 = new Bar1();
bar1.setId( 1 );
bar1.setBar1( "bar 1" );
bar1.setBarType( "1" );
final FooEmbeddable foo1Embedded = new FooEmbeddable();
foo1Embedded.setBar( bar1 );
foo1.setFooEmbedded( foo1Embedded );
session.persist( bar1 );
session.persist( foo1 );
}
);
}
@AfterEach
public void dropTestData(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.createQuery( "delete Bar2" ).executeUpdate();
session.createQuery( "delete Bar1" ).executeUpdate();
session.createQuery( "delete Foo" ).executeUpdate();
}
);
}
@Test
public void testEmbeddedAny() {
doInJPA( this::entityManagerFactory, em -> {
Foo foo1 = new Foo();
foo1.setId( 1 );
Bar1 bar1 = new Bar1();
bar1.setId( 1 );
bar1.setBar1( "bar 1" );
bar1.setBarType( "1" );
FooEmbeddable foo1Embedded = new FooEmbeddable();
foo1Embedded.setBar( bar1 );
foo1.setFooEmbedded( foo1Embedded );
em.persist( bar1 );
em.persist( foo1 );
} );
doInJPA( this::entityManagerFactory, em -> {
Foo foo2 = new Foo();
foo2.setId( 2 );
Bar2 bar2 = new Bar2();
bar2.setId( 2 );
bar2.setBar2( "bar 2" );
bar2.setBarType( "2" );
FooEmbeddable foo2Embedded = new FooEmbeddable();
foo2Embedded.setBar( bar2 );
foo2.setFooEmbedded( foo2Embedded );
em.persist( bar2 );
em.persist( foo2 );
} );
doInJPA( this::entityManagerFactory, em -> {
Foo foo1 = em.find( Foo.class, 1 );
assertTrue( foo1.getFooEmbedded().getBar() instanceof Bar1 );
assertEquals( "bar 1", ( (Bar1) foo1.getFooEmbedded().getBar() ).getBar1() );
} );
doInJPA( this::entityManagerFactory, em -> {
Foo foo2 = em.find( Foo.class, 2 );
assertTrue( foo2.getFooEmbedded().getBar() instanceof Bar2 );
assertEquals( "bar 2", ( (Bar2) foo2.getFooEmbedded().getBar() ).getBar2() );
} );
public void testEmbeddedAny(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final Foo foo = session.find( Foo.class, 1 );
assertTrue( foo.getFooEmbedded().getBar() instanceof Bar1 );
assertEquals( "bar 1", ( (Bar1) foo.getFooEmbedded().getBar() ).getBar1() );
}
);
}
@Entity(name = "Foo")

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.test.annotations.any;
package org.hibernate.orm.test.any.annotations;
import javax.persistence.Column;
import javax.persistence.Entity;

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.test.annotations.any;
package org.hibernate.orm.test.any.annotations;
import javax.persistence.Column;
import javax.persistence.Entity;

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.test.annotations.any;
package org.hibernate.orm.test.any.annotations;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.test.annotations.any;
package org.hibernate.orm.test.any.annotations;
public interface Property {

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.test.annotations.any;
package org.hibernate.orm.test.any.annotations;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.test.annotations.any;
package org.hibernate.orm.test.any.annotations;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.Column;

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.test.annotations.any;
package org.hibernate.orm.test.any.annotations;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.test.annotations.any;
package org.hibernate.orm.test.any.annotations;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

View File

@ -1,8 +1,8 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
// $Id$
@ -14,7 +14,7 @@
@MetaValue(value = "L", targetEntity = LongProperty.class)
})
package org.hibernate.test.annotations.any;
package org.hibernate.orm.test.any.annotations;
import org.hibernate.annotations.AnyMetaDef;
import org.hibernate.annotations.MetaValue;

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.any;
package org.hibernate.orm.test.any.hbm;
import java.util.HashSet;
import java.util.Set;

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.any;
package org.hibernate.orm.test.any.hbm;
import org.hibernate.Hibernate;
import org.hibernate.stat.spi.StatisticsImplementor;
@ -12,10 +12,10 @@ import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.test.annotations.any.IntegerProperty;
import org.hibernate.test.annotations.any.Property;
import org.hibernate.test.annotations.any.PropertySet;
import org.hibernate.test.annotations.any.StringProperty;
import org.hibernate.orm.test.any.annotations.IntegerProperty;
import org.hibernate.orm.test.any.annotations.Property;
import org.hibernate.orm.test.any.annotations.PropertySet;
import org.hibernate.orm.test.any.annotations.StringProperty;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -28,7 +28,7 @@ import static org.junit.Assert.assertTrue;
@DomainModel(
annotatedClasses = { StringProperty.class, IntegerProperty.class },
xmlMappings = "org/hibernate/orm/test/any/AnyTestEagerPropertySet.hbm.xml"
xmlMappings = "org/hibernate/orm/test/any/hbm/AnyTestEagerPropertySet.hbm.xml"
)
@SessionFactory( generateStatistics = true )
public class AnyEagerHbmTest {

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.any;
package org.hibernate.orm.test.any.hbm;
import org.hibernate.Hibernate;
import org.hibernate.stat.spi.StatisticsImplementor;
@ -12,10 +12,10 @@ import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.test.annotations.any.IntegerProperty;
import org.hibernate.test.annotations.any.LazyPropertySet;
import org.hibernate.test.annotations.any.Property;
import org.hibernate.test.annotations.any.StringProperty;
import org.hibernate.orm.test.any.annotations.IntegerProperty;
import org.hibernate.orm.test.any.annotations.LazyPropertySet;
import org.hibernate.orm.test.any.annotations.Property;
import org.hibernate.orm.test.any.annotations.StringProperty;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -28,7 +28,7 @@ import static org.junit.Assert.assertTrue;
@DomainModel(
annotatedClasses = { StringProperty.class, IntegerProperty.class },
xmlMappings = "org/hibernate/orm/test/any/AnyTestLazyPropertySet.hbm.xml"
xmlMappings = "org/hibernate/orm/test/any/hbm/AnyTestLazyPropertySet.hbm.xml"
)
@SessionFactory( generateStatistics = true )
public class AnyLazyHbmTest {

View File

@ -9,7 +9,7 @@
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.test.annotations.any">
<hibernate-mapping package="org.hibernate.orm.test.any.annotations">
<class name="PropertySet" table="eager_property_set">
<id name="id" type="java.lang.Integer">
<generator class="increment"/>

View File

@ -2,14 +2,14 @@
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later
~ See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
-->
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.test.annotations.any">
<hibernate-mapping package="org.hibernate.orm.test.any.annotations">
<class name="LazyPropertySet" table="lazy_property_set">
<id name="id" type="java.lang.Integer">
<generator class="increment"/>

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.any;
package org.hibernate.orm.test.any.hbm;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.query.SemanticException;
@ -27,7 +27,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
*/
@TestForIssue(jiraKey = "HHH-1663")
@ServiceRegistry( settings = @ServiceRegistry.Setting( name = AvailableSettings.USE_SECOND_LEVEL_CACHE, value = "false" ) )
@DomainModel( xmlMappings = "org/hibernate/orm/test/any/Person.hbm.xml" )
@DomainModel( xmlMappings = "org/hibernate/orm/test/any/hbm/Person.hbm.xml" )
@SessionFactory
public class AnyTypeTest {

View File

@ -9,7 +9,7 @@
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.orm.test.any">
<hibernate-mapping package="org.hibernate.orm.test.any.hbm">
<class name="Person" table="T_ANY_PERSON">
<id name="id" column="ID_">

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.any;
package org.hibernate.orm.test.any.hbm;
/**

View File

@ -1,240 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.annotations.any;
import org.hibernate.LazyInitializationException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.query.Query;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class AnyTest extends BaseCoreFunctionalTestCase {
@Override
protected boolean isCleanupTestDataRequired() {
return true;
}
@Test
public void testDefaultAnyAssociation() {
Session s = openSession();
Transaction t = s.beginTransaction();
PropertySet set1 = new PropertySet( "string" );
Property property = new StringProperty( "name", "Alex" );
set1.setSomeProperty( property );
set1.addGeneralProperty( property );
s.save( set1 );
PropertySet set2 = new PropertySet( "integer" );
property = new IntegerProperty( "age", 33 );
set2.setSomeProperty( property );
set2.addGeneralProperty( property );
s.save( set2 );
s.flush();
s.clear();
Query q = s
.createQuery( "select s from PropertySet s where name = :name" );
q.setParameter( "name", "string" );
PropertySet result = (PropertySet) q.uniqueResult();
assertNotNull( result );
assertNotNull( result.getSomeProperty() );
assertTrue( result.getSomeProperty() instanceof StringProperty );
assertEquals( "Alex", result.getSomeProperty().asString() );
assertNotNull( result.getGeneralProperties() );
assertEquals( 1, result.getGeneralProperties().size() );
assertEquals( "Alex", result.getGeneralProperties().get( 0 ).asString() );
q.setParameter( "name", "integer" );
result = (PropertySet) q.uniqueResult();
assertNotNull( result );
assertNotNull( result.getSomeProperty() );
assertTrue( result.getSomeProperty() instanceof IntegerProperty );
assertEquals( "33", result.getSomeProperty().asString() );
assertNotNull( result.getGeneralProperties() );
assertEquals( 1, result.getGeneralProperties().size() );
assertEquals( "33", result.getGeneralProperties().get( 0 ).asString() );
t.rollback();
s.close();
}
@Test
public void testManyToAnyWithMap() throws Exception {
Session s = openSession();
Transaction t = s.beginTransaction();
PropertyMap map = new PropertyMap( "sample" );
map.getProperties().put( "name", new StringProperty( "name", "Alex" ) );
map.getProperties().put( "age", new IntegerProperty( "age", 33 ) );
s.save( map );
s.flush();
s.clear();
Query q = s
.createQuery( "SELECT map FROM PropertyMap map WHERE map.name = :name" );
q.setParameter( "name", "sample" );
PropertyMap actualMap = (PropertyMap) q.uniqueResult();
assertNotNull( actualMap );
assertNotNull( actualMap.getProperties() );
Property property = actualMap.getProperties().get( "name" );
assertNotNull( property );
assertTrue( property instanceof StringProperty );
assertEquals( "Alex", property.asString() );
property = actualMap.getProperties().get( "age" );
assertNotNull( property );
assertTrue( property instanceof IntegerProperty );
assertEquals( "33", property.asString() );
t.rollback();
s.close();
}
@Test
public void testMetaDataUseWithManyToAny() {
Session s = openSession();
Transaction t = s.beginTransaction();
PropertyList list = new PropertyList( "sample" );
StringProperty stringProperty = new StringProperty( "name", "Alex" );
IntegerProperty integerProperty = new IntegerProperty( "age", 33 );
LongProperty longProperty = new LongProperty( "distance", 121L );
CharProperty charProp = new CharProperty( "Est", 'E' );
list.setSomeProperty( longProperty );
list.addGeneralProperty( stringProperty );
list.addGeneralProperty( integerProperty );
list.addGeneralProperty( longProperty );
list.addGeneralProperty( charProp );
s.save( list );
s.flush();
s.clear();
Query q = s
.createQuery( "SELECT list FROM PropertyList list WHERE list.name = :name" );
q.setParameter( "name", "sample" );
PropertyList<Property> actualList = (PropertyList<Property>) q
.uniqueResult();
assertNotNull( actualList );
assertNotNull( actualList.getGeneralProperties() );
assertEquals( 4, actualList.getGeneralProperties().size() );
Property property = actualList.getSomeProperty();
assertNotNull( property );
assertTrue( property instanceof LongProperty );
assertEquals( "121", property.asString() );
assertEquals( "Alex", actualList.getGeneralProperties().get( 0 )
.asString() );
assertEquals( "33", actualList.getGeneralProperties().get( 1 ).asString() );
assertEquals( "121", actualList.getGeneralProperties().get( 2 ).asString() );
assertEquals( "E", actualList.getGeneralProperties().get( 3 ).asString() );
t.rollback();
s.close();
}
@Test
public void testFetchEager() {
doInHibernate( this::sessionFactory, s -> {
PropertySet set = new PropertySet( "string" );
Property property = new StringProperty( "name", "Alex" );
set.setSomeProperty( property );
s.save( set );
} );
PropertySet result = doInHibernate( this::sessionFactory, s -> {
return s.createQuery( "select s from PropertySet s where name = :name", PropertySet.class )
.setParameter( "name", "string" )
.getSingleResult();
} );
assertNotNull( result );
assertNotNull( result.getSomeProperty() );
assertTrue( result.getSomeProperty() instanceof StringProperty );
assertEquals( "Alex", result.getSomeProperty().asString() );
}
@Test
public void testFetchLazy() {
doInHibernate( this::sessionFactory, s -> {
LazyPropertySet set = new LazyPropertySet( "string" );
Property property = new StringProperty( "name", "Alex" );
set.setSomeProperty( property );
s.save( set );
} );
LazyPropertySet result = doInHibernate( this::sessionFactory, s -> {
return s.createQuery( "select s from LazyPropertySet s where name = :name", LazyPropertySet.class )
.setParameter( "name", "string" )
.getSingleResult();
} );
assertNotNull( result );
assertNotNull( result.getSomeProperty() );
try {
result.getSomeProperty().asString();
fail( "should not get the property string after session closed." );
}
catch (LazyInitializationException e) {
// expected
}
catch (Exception e) {
fail( "should not throw exception other than LazyInitializationException." );
}
}
@Override
protected Class[] getAnnotatedClasses() {
return new Class[] {
StringProperty.class,
IntegerProperty.class,
LongProperty.class,
PropertySet.class,
LazyPropertySet.class,
PropertyMap.class,
PropertyList.class,
CharProperty.class
};
}
@Override
protected String[] getAnnotatedPackages() {
return new String[] {
"org.hibernate.test.annotations.any"
};
}
// Simply having this orm.xml file in the classpath reproduces HHH-4261.
@Override
protected String[] getOrmXmlFiles() {
return new String[] { "org/hibernate/test/annotations/any/orm.xml" };
}
}

View File

@ -2,8 +2,8 @@
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later
~ See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
-->
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

View File

@ -96,6 +96,7 @@ public @interface DomainModel {
Class<? extends DomainModelDescriptor>[] modelDescriptorClasses() default {};
Class[] annotatedClasses() default {};
String[] annotatedClassNames() default {};
String[] annotatedPackageNames() default {};
String[] xmlMappings() default {};
ExtraQueryImport[] extraQueryImports() default {};
Class<?>[] extraQueryImportClasses() default {};

View File

@ -16,6 +16,7 @@ import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.internal.util.JavaHelper;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
@ -88,6 +89,10 @@ public class DomainModelExtension
final MetadataSources metadataSources = new MetadataSources( serviceRegistry );
for ( String annotatedPackageName : domainModelAnnotation.annotatedPackageNames() ) {
metadataSources.addPackage( JavaHelper.getPackageFor( annotatedPackageName ) );
}
for ( StandardDomainModel standardDomainModel : domainModelAnnotation.standardModels() ) {
standardDomainModel.getDescriptor().applyDomainModel( metadataSources );
}