HHH-9055 - Binding support for IdClass and MapsId needs a complete review
This commit is contained in:
parent
3cd4ae6c2a
commit
545516328a
|
@ -549,15 +549,9 @@ public class JoinWalker {
|
||||||
final Type idType = persister.getIdentifierType();
|
final Type idType = persister.getIdentifierType();
|
||||||
if ( idType.isComponentType() ) {
|
if ( idType.isComponentType() ) {
|
||||||
final CompositeType cidType = (CompositeType) idType;
|
final CompositeType cidType = (CompositeType) idType;
|
||||||
if ( cidType.isEmbedded() ) {
|
if ( persister.getEntityMetamodel().getIdentifierProperty().isVirtual() ) {
|
||||||
// we have an embedded composite identifier. Most likely we need to process the composite
|
// we have a non-aggregated composite identifier. We need to process
|
||||||
// properties separately, although there is an edge case where the identifier is really
|
// the composite sub-properties separately
|
||||||
// a simple identifier (single value) wrapped in a JPA @IdClass or even in the case of a
|
|
||||||
// a simple identifier (single value) wrapped in a Hibernate composite type.
|
|
||||||
//
|
|
||||||
// We really do not have a built-in method to determine that. However, generally the
|
|
||||||
// persister would report that there is single, physical identifier property which is
|
|
||||||
// explicitly at odds with the notion of "embedded composite". So we use that for now
|
|
||||||
if ( persister.getEntityMetamodel().getIdentifierProperty().isEmbedded() ) {
|
if ( persister.getEntityMetamodel().getIdentifierProperty().isEmbedded() ) {
|
||||||
walkComponentTree(
|
walkComponentTree(
|
||||||
cidType,
|
cidType,
|
||||||
|
@ -570,6 +564,27 @@ public class JoinWalker {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// if ( cidType.isEmbedded() ) {
|
||||||
|
// // we have an embedded composite identifier. Most likely we need to process the composite
|
||||||
|
// // properties separately, although there is an edge case where the identifier is really
|
||||||
|
// // a simple identifier (single value) wrapped in a JPA @IdClass or even in the case of a
|
||||||
|
// // a simple identifier (single value) wrapped in a Hibernate composite type.
|
||||||
|
// //
|
||||||
|
// // We really do not have a built-in method to determine that. However, generally the
|
||||||
|
// // persister would report that there is single, physical identifier property which is
|
||||||
|
// // explicitly at odds with the notion of "embedded composite". So we use that for now
|
||||||
|
// if ( persister.getEntityMetamodel().getIdentifierProperty().isEmbedded() ) {
|
||||||
|
// walkComponentTree(
|
||||||
|
// cidType,
|
||||||
|
// -1,
|
||||||
|
// 0,
|
||||||
|
// persister,
|
||||||
|
// alias,
|
||||||
|
// path,
|
||||||
|
// currentDepth
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -538,7 +538,7 @@ public class EntityBinding extends AbstractAttributeBindingContainer implements
|
||||||
getPathBase(),
|
getPathBase(),
|
||||||
idAttributeBindings
|
idAttributeBindings
|
||||||
);
|
);
|
||||||
registerAttributeBinding( binding );
|
// registerAttributeBinding( binding );
|
||||||
return binding;
|
return binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,9 +48,15 @@ import static org.hibernate.id.EntityIdentifierNature.NON_AGGREGATED_COMPOSITE;
|
||||||
import static org.hibernate.id.EntityIdentifierNature.SIMPLE;
|
import static org.hibernate.id.EntityIdentifierNature.SIMPLE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hold information about the entity identifier. At a high-level, can be one of 2-types:<ul>
|
* Hold information about the entity identifier. At a high-level, can be one of
|
||||||
* <li>single-attribute identifier - this includes both simple identifiers and aggregated composite identifiers</li>
|
* 2 types:<ul>
|
||||||
* <li>multiple-attribute identifier - non-aggregated composite identifiers</li>
|
* <li>
|
||||||
|
* single-attribute identifier - this includes both simple identifiers
|
||||||
|
* and aggregated composite identifiers
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* multi-attribute identifier - non-aggregated composite identifiers
|
||||||
|
* </li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.hibernate.engine.spi.CascadeStyles;
|
||||||
import org.hibernate.engine.spi.IdentifierValue;
|
import org.hibernate.engine.spi.IdentifierValue;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.VersionValue;
|
import org.hibernate.engine.spi.VersionValue;
|
||||||
|
import org.hibernate.id.EntityIdentifierNature;
|
||||||
import org.hibernate.id.IdentifierGenerator;
|
import org.hibernate.id.IdentifierGenerator;
|
||||||
import org.hibernate.internal.util.ReflectHelper;
|
import org.hibernate.internal.util.ReflectHelper;
|
||||||
import org.hibernate.mapping.KeyValue;
|
import org.hibernate.mapping.KeyValue;
|
||||||
|
@ -58,6 +59,7 @@ import org.hibernate.tuple.entity.EntityBasedBasicAttribute;
|
||||||
import org.hibernate.tuple.entity.EntityBasedCompositionAttribute;
|
import org.hibernate.tuple.entity.EntityBasedCompositionAttribute;
|
||||||
import org.hibernate.tuple.entity.VersionProperty;
|
import org.hibernate.tuple.entity.VersionProperty;
|
||||||
import org.hibernate.type.AssociationType;
|
import org.hibernate.type.AssociationType;
|
||||||
|
import org.hibernate.type.ComponentType;
|
||||||
import org.hibernate.type.CompositeType;
|
import org.hibernate.type.CompositeType;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
import org.hibernate.type.VersionType;
|
import org.hibernate.type.VersionType;
|
||||||
|
@ -138,22 +140,21 @@ public final class PropertyFactory {
|
||||||
// see org.hibernate.metamodel.spi.domain.AbstractAttributeContainer.locateOrCreateVirtualAttribute()
|
// see org.hibernate.metamodel.spi.domain.AbstractAttributeContainer.locateOrCreateVirtualAttribute()
|
||||||
|
|
||||||
final String mappedUnsavedValue = mappedEntity.getHierarchyDetails().getEntityIdentifier().getUnsavedValue();
|
final String mappedUnsavedValue = mappedEntity.getHierarchyDetails().getEntityIdentifier().getUnsavedValue();
|
||||||
final Type type;
|
|
||||||
if ( mappedEntity.getHierarchyDetails().getEntityIdentifier().isIdentifierMapper() ) {
|
if ( mappedEntity.getHierarchyDetails().getEntityIdentifier().getNature()
|
||||||
type = sessionFactory.getTypeResolver().getTypeFactory().component(
|
== EntityIdentifierNature.NON_AGGREGATED_COMPOSITE ) {
|
||||||
|
// the "attribute" will need to be virtual since there is no single
|
||||||
|
// attribute identifying the identifier
|
||||||
|
final ComponentType type = sessionFactory.getTypeResolver().getTypeFactory().component(
|
||||||
new ComponentMetamodel(
|
new ComponentMetamodel(
|
||||||
sessionFactory.getServiceRegistry(),
|
sessionFactory.getServiceRegistry(),
|
||||||
( (EmbeddedAttributeBinding) attributeBinding ).getEmbeddableBinding(),
|
( (EmbeddedAttributeBinding) attributeBinding ).getEmbeddableBinding(),
|
||||||
true,
|
true,
|
||||||
true
|
mappedEntity.getHierarchyDetails().getEntityIdentifier().getLookupClassBinding().definedIdClass()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
|
||||||
else {
|
|
||||||
type = attributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping();
|
|
||||||
}
|
|
||||||
|
|
||||||
IdentifierValue unsavedValue = UnsavedValueFactory.getUnsavedIdentifierValue(
|
final IdentifierValue unsavedValue = UnsavedValueFactory.getUnsavedIdentifierValue(
|
||||||
mappedUnsavedValue,
|
mappedUnsavedValue,
|
||||||
getGetter( attributeBinding, sessionFactory ),
|
getGetter( attributeBinding, sessionFactory ),
|
||||||
type,
|
type,
|
||||||
|
@ -163,23 +164,32 @@ public final class PropertyFactory {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( attributeBinding.getAttribute().isSynthetic() ) {
|
|
||||||
// this is a virtual id property...
|
|
||||||
return new IdentifierProperty(
|
return new IdentifierProperty(
|
||||||
type,
|
type,
|
||||||
mappedEntity.getHierarchyDetails().getEntityIdentifier().isNonAggregatedComposite() &&
|
true,
|
||||||
mappedEntity.getHierarchyDetails().getEntityIdentifier().getIdClassClass() == null,
|
mappedEntity.getHierarchyDetails().getEntityIdentifier().getLookupClassBinding().definedIdClass(),
|
||||||
mappedEntity.getHierarchyDetails().getEntityIdentifier().isIdentifierMapper(),
|
|
||||||
unsavedValue,
|
unsavedValue,
|
||||||
generator
|
generator
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
final Type type = attributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping();
|
||||||
|
|
||||||
|
final IdentifierValue unsavedValue = UnsavedValueFactory.getUnsavedIdentifierValue(
|
||||||
|
mappedUnsavedValue,
|
||||||
|
getGetter( attributeBinding, sessionFactory ),
|
||||||
|
type,
|
||||||
|
getConstructor(
|
||||||
|
mappedEntity,
|
||||||
|
sessionFactory.getServiceRegistry().getService( ClassLoaderService.class )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
return new IdentifierProperty(
|
return new IdentifierProperty(
|
||||||
attributeBinding.getAttribute().getName(),
|
attributeBinding.getAttribute().getName(),
|
||||||
null,
|
null,
|
||||||
type,
|
type,
|
||||||
mappedEntity.getHierarchyDetails().getEntityIdentifier().isNonAggregatedComposite(),
|
false,
|
||||||
unsavedValue,
|
unsavedValue,
|
||||||
generator
|
generator
|
||||||
);
|
);
|
||||||
|
|
|
@ -46,8 +46,6 @@ import org.hibernate.id.Assigned;
|
||||||
import org.hibernate.internal.CoreLogging;
|
import org.hibernate.internal.CoreLogging;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
import org.hibernate.loader.PropertyPath;
|
import org.hibernate.loader.PropertyPath;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
|
||||||
import org.hibernate.mapping.Property;
|
|
||||||
import org.hibernate.metamodel.spi.binding.AttributeBinding;
|
import org.hibernate.metamodel.spi.binding.AttributeBinding;
|
||||||
import org.hibernate.metamodel.spi.binding.EntityBinding;
|
import org.hibernate.metamodel.spi.binding.EntityBinding;
|
||||||
import org.hibernate.metamodel.spi.binding.EntityIdentifier;
|
import org.hibernate.metamodel.spi.binding.EntityIdentifier;
|
||||||
|
@ -238,7 +236,10 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer {
|
||||||
@Override
|
@Override
|
||||||
public Serializable getIdentifier(Object entity, SessionImplementor session) {
|
public Serializable getIdentifier(Object entity, SessionImplementor session) {
|
||||||
final Object id;
|
final Object id;
|
||||||
if ( entityMetamodel.getIdentifierProperty().isEmbedded() ) {
|
if ( identifierMapperType != null ) {
|
||||||
|
id = mappedIdentifierValueMarshaller.getIdentifier( entity, getEntityMode(), session );
|
||||||
|
}
|
||||||
|
else if ( entityMetamodel.getIdentifierProperty().isEmbedded() ) {
|
||||||
id = entity;
|
id = entity;
|
||||||
}
|
}
|
||||||
else if ( HibernateProxy.class.isInstance( entity ) ) {
|
else if ( HibernateProxy.class.isInstance( entity ) ) {
|
||||||
|
@ -246,13 +247,8 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ( idGetter == null ) {
|
if ( idGetter == null ) {
|
||||||
if (identifierMapperType==null) {
|
|
||||||
throw new HibernateException( "The class has no identifier property: " + getEntityName() );
|
throw new HibernateException( "The class has no identifier property: " + getEntityName() );
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
id = mappedIdentifierValueMarshaller.getIdentifier( entity, getEntityMode(), session );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
id = idGetter.get( entity );
|
id = idGetter.get( entity );
|
||||||
}
|
}
|
||||||
|
@ -282,7 +278,10 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setIdentifier(Object entity, Serializable id, SessionImplementor session) {
|
public void setIdentifier(Object entity, Serializable id, SessionImplementor session) {
|
||||||
if ( entityMetamodel.getIdentifierProperty().isEmbedded() ) {
|
if ( identifierMapperType != null && identifierMapperType.getReturnedClass().isInstance( id ) ) {
|
||||||
|
mappedIdentifierValueMarshaller.setIdentifier( entity, id, getEntityMode(), session );
|
||||||
|
}
|
||||||
|
else if ( entityMetamodel.getIdentifierProperty().isEmbedded() ) {
|
||||||
if ( entity != id ) {
|
if ( entity != id ) {
|
||||||
CompositeType copier = (CompositeType) entityMetamodel.getIdentifierProperty().getType();
|
CompositeType copier = (CompositeType) entityMetamodel.getIdentifierProperty().getType();
|
||||||
copier.setPropertyValues( entity, copier.getPropertyValues( id, getEntityMode() ), getEntityMode() );
|
copier.setPropertyValues( entity, copier.getPropertyValues( id, getEntityMode() ), getEntityMode() );
|
||||||
|
@ -291,8 +290,11 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer {
|
||||||
else if ( idSetter != null ) {
|
else if ( idSetter != null ) {
|
||||||
idSetter.set( entity, id, getFactory() );
|
idSetter.set( entity, id, getFactory() );
|
||||||
}
|
}
|
||||||
else if ( identifierMapperType != null ) {
|
else {
|
||||||
mappedIdentifierValueMarshaller.setIdentifier( entity, id, getEntityMode(), session );
|
throw new IllegalArgumentException(
|
||||||
|
"Could not determine how to set given value [" + id
|
||||||
|
+ "] as identifier value for entity [" + getEntityName() + "]"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.metamodel.spi.binding;
|
||||||
|
|
||||||
|
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class BindingHelper {
|
||||||
|
/**
|
||||||
|
* Help to get an attribute binding that we are fully expecting to exist.
|
||||||
|
* <p/>
|
||||||
|
* Helpful because it validates that the attribute exists and manages checking the
|
||||||
|
* specific type and casting.
|
||||||
|
*
|
||||||
|
* @param attributeContainer The container for the attribute
|
||||||
|
* @param attributeName The name of the attribute to get
|
||||||
|
* @param expectedType The specific AttributeBinding sub-type we are expecting
|
||||||
|
* @param <T> The generic representation of `expectedType`
|
||||||
|
*
|
||||||
|
* @return The typed attribute binding
|
||||||
|
*/
|
||||||
|
public static <T extends AttributeBinding> T locateAttributeBinding(
|
||||||
|
AttributeBindingContainer attributeContainer,
|
||||||
|
String attributeName,
|
||||||
|
Class<T> expectedType) {
|
||||||
|
AttributeBinding attributeBinding = attributeContainer.locateAttributeBinding( attributeName );
|
||||||
|
assertNotNull( "Could not locate attribute named " + attributeName, attributeBinding );
|
||||||
|
return assertTyping( expectedType, attributeBinding );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,33 +23,40 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.metamodel.spi.binding.cid;
|
package org.hibernate.metamodel.spi.binding.cid;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Embeddable;
|
import javax.persistence.Embeddable;
|
||||||
import javax.persistence.EmbeddedId;
|
import javax.persistence.EmbeddedId;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
|
|
||||||
import org.hibernate.id.EntityIdentifierNature;
|
import org.hibernate.id.EntityIdentifierNature;
|
||||||
import org.hibernate.metamodel.spi.binding.AttributeBinding;
|
|
||||||
import org.hibernate.metamodel.spi.binding.AttributeBindingContainer;
|
|
||||||
import org.hibernate.metamodel.spi.binding.BasicAttributeBinding;
|
import org.hibernate.metamodel.spi.binding.BasicAttributeBinding;
|
||||||
import org.hibernate.metamodel.spi.binding.EmbeddedAttributeBinding;
|
import org.hibernate.metamodel.spi.binding.EmbeddedAttributeBinding;
|
||||||
import org.hibernate.metamodel.spi.binding.EntityBinding;
|
import org.hibernate.metamodel.spi.binding.EntityBinding;
|
||||||
|
import org.hibernate.metamodel.spi.binding.RelationalValueBinding;
|
||||||
import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
|
import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
|
||||||
|
|
||||||
import org.hibernate.testing.junit4.BaseAnnotationBindingTestCase;
|
import org.hibernate.testing.junit4.BaseAnnotationBindingTestCase;
|
||||||
import org.hibernate.testing.junit4.Resources;
|
import org.hibernate.testing.junit4.Resources;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hibernate.metamodel.spi.binding.BindingHelper.locateAttributeBinding;
|
||||||
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertSame;
|
import static org.junit.Assert.assertSame;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Assertions about the metamodel interpretations of basic {@link javax.persistence.EmbeddedId} usage.
|
||||||
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
*
|
||||||
|
* @see org.hibernate.metamodel.spi.binding.cid.BasicIdClassTest
|
||||||
*/
|
*/
|
||||||
public class BasicEmbeddedIdTest extends BaseAnnotationBindingTestCase {
|
public class BasicEmbeddedIdTest extends BaseAnnotationBindingTestCase {
|
||||||
@Embeddable
|
@Embeddable
|
||||||
public static class CoursePK {
|
public static class CoursePK {
|
||||||
|
@Column( name = "dept" )
|
||||||
public String department;
|
public String department;
|
||||||
public String code;
|
public String code;
|
||||||
}
|
}
|
||||||
|
@ -64,30 +71,61 @@ public class BasicEmbeddedIdTest extends BaseAnnotationBindingTestCase {
|
||||||
@Test
|
@Test
|
||||||
@Resources( annotatedClasses = {CoursePK.class, Course.class} )
|
@Resources( annotatedClasses = {CoursePK.class, Course.class} )
|
||||||
public void testBasicUsage() {
|
public void testBasicUsage() {
|
||||||
|
// get the Course entity binding
|
||||||
EntityBinding courseBinding = getEntityBinding( Course.class );
|
EntityBinding courseBinding = getEntityBinding( Course.class );
|
||||||
assertEquals( 2, courseBinding.getAttributeBindingClosureSpan() );
|
assertNotNull( courseBinding );
|
||||||
|
|
||||||
EmbeddedAttributeBinding keyBinding = locateAttributeBinding( courseBinding, "key", EmbeddedAttributeBinding.class );
|
|
||||||
assertEquals( 2, keyBinding.getEmbeddableBinding().attributeBindingSpan() );
|
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
EntityIdentifierNature.AGGREGATED_COMPOSITE,
|
EntityIdentifierNature.AGGREGATED_COMPOSITE,
|
||||||
courseBinding.getHierarchyDetails().getEntityIdentifier().getNature()
|
courseBinding.getHierarchyDetails().getEntityIdentifier().getNature()
|
||||||
);
|
);
|
||||||
|
assertNull(
|
||||||
|
courseBinding.getHierarchyDetails().getEntityIdentifier().getLookupClassBinding().getIdClassType()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Course should be interpreted as defining 2 attributes: `key` and `title`
|
||||||
|
assertEquals( 2, courseBinding.getAttributeBindingClosureSpan() );
|
||||||
|
|
||||||
|
// just make sure `title` is one of them
|
||||||
|
locateAttributeBinding( courseBinding, "title", BasicAttributeBinding.class );
|
||||||
|
|
||||||
|
// locate the attribute binding for `key` which is the EmbeddedId attribute
|
||||||
|
EmbeddedAttributeBinding keyBinding = locateAttributeBinding(
|
||||||
|
courseBinding,
|
||||||
|
"key",
|
||||||
|
EmbeddedAttributeBinding.class
|
||||||
|
);
|
||||||
SingularAttributeBinding identifierAttribute = courseBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding();
|
SingularAttributeBinding identifierAttribute = courseBinding.getHierarchyDetails().getEntityIdentifier().getAttributeBinding();
|
||||||
// NOTE : same does '=='
|
// NOTE : assertSame() does '=='
|
||||||
assertSame( keyBinding, identifierAttribute );
|
assertSame( keyBinding, identifierAttribute );
|
||||||
|
|
||||||
BasicAttributeBinding titleBinding = locateAttributeBinding( courseBinding, "title", BasicAttributeBinding.class );
|
// the Embeddable for `key` (CoursePK) should also define 2 attributes: `department` and `code`
|
||||||
}
|
assertEquals( 2, keyBinding.getEmbeddableBinding().attributeBindingSpan() );
|
||||||
|
|
||||||
private <T extends AttributeBinding> T locateAttributeBinding(
|
BasicAttributeBinding deptAttribute = locateAttributeBinding(
|
||||||
AttributeBindingContainer attributeContainer,
|
keyBinding.getEmbeddableBinding(),
|
||||||
String attributeName,
|
"department",
|
||||||
Class<T> expectedType) {
|
BasicAttributeBinding.class
|
||||||
AttributeBinding attributeBinding = attributeContainer.locateAttributeBinding( attributeName );
|
);
|
||||||
assertNotNull( "Could not locate attribute named " + attributeName, attributeBinding );
|
assertEquals( 1, deptAttribute.getRelationalValueBindings().size() );
|
||||||
return assertTyping( expectedType, attributeBinding );
|
RelationalValueBinding deptColumnBinding = deptAttribute.getRelationalValueBindings().get( 0 );
|
||||||
|
org.hibernate.metamodel.spi.relational.Column deptColumn = assertTyping(
|
||||||
|
org.hibernate.metamodel.spi.relational.Column.class,
|
||||||
|
deptColumnBinding.getValue()
|
||||||
|
);
|
||||||
|
assertEquals( "dept", deptColumn.getColumnName().getText() );
|
||||||
|
|
||||||
|
BasicAttributeBinding codeAttribute = locateAttributeBinding(
|
||||||
|
keyBinding.getEmbeddableBinding(),
|
||||||
|
"code",
|
||||||
|
BasicAttributeBinding.class
|
||||||
|
);
|
||||||
|
assertEquals( 1, codeAttribute.getRelationalValueBindings().size() );
|
||||||
|
RelationalValueBinding codeColumnBinding = codeAttribute.getRelationalValueBindings().get( 0 );
|
||||||
|
org.hibernate.metamodel.spi.relational.Column codeColumn = assertTyping(
|
||||||
|
org.hibernate.metamodel.spi.relational.Column.class,
|
||||||
|
codeColumnBinding.getValue()
|
||||||
|
);
|
||||||
|
assertEquals( "code", codeColumn.getColumnName().getText() );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.metamodel.spi.binding.cid;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.IdClass;
|
||||||
|
|
||||||
|
import org.hibernate.id.EntityIdentifierNature;
|
||||||
|
import org.hibernate.metamodel.spi.binding.AttributeBinding;
|
||||||
|
import org.hibernate.metamodel.spi.binding.BasicAttributeBinding;
|
||||||
|
import org.hibernate.metamodel.spi.binding.EmbeddableBinding;
|
||||||
|
import org.hibernate.metamodel.spi.binding.EmbeddedAttributeBinding;
|
||||||
|
import org.hibernate.metamodel.spi.binding.EntityBinding;
|
||||||
|
import org.hibernate.metamodel.spi.binding.RelationalValueBinding;
|
||||||
|
|
||||||
|
import org.hibernate.testing.junit4.BaseAnnotationBindingTestCase;
|
||||||
|
import org.hibernate.testing.junit4.Resources;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hibernate.metamodel.spi.binding.BindingHelper.locateAttributeBinding;
|
||||||
|
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assertions about the metamodel interpretations of basic {@link javax.persistence.IdClass} usage.
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*
|
||||||
|
* @see org.hibernate.metamodel.spi.binding.cid.BasicEmbeddedIdTest
|
||||||
|
*/
|
||||||
|
public class BasicIdClassTest extends BaseAnnotationBindingTestCase {
|
||||||
|
public static class CoursePK {
|
||||||
|
public String department;
|
||||||
|
public String code;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@IdClass( CoursePK.class )
|
||||||
|
public static class Course {
|
||||||
|
@Id
|
||||||
|
@Column( name = "dept" )
|
||||||
|
public String department;
|
||||||
|
@Id
|
||||||
|
public String code;
|
||||||
|
private String title;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Resources( annotatedClasses = Course.class )
|
||||||
|
public void testBasicUsage() {
|
||||||
|
// get the Course entity binding
|
||||||
|
EntityBinding courseBinding = getEntityBinding( Course.class );
|
||||||
|
assertNotNull( courseBinding );
|
||||||
|
assertEquals(
|
||||||
|
EntityIdentifierNature.NON_AGGREGATED_COMPOSITE,
|
||||||
|
courseBinding.getHierarchyDetails().getEntityIdentifier().getNature()
|
||||||
|
);
|
||||||
|
Class idClassClass = courseBinding.getHierarchyDetails().getEntityIdentifier()
|
||||||
|
.getLookupClassBinding()
|
||||||
|
.getIdClassType();
|
||||||
|
assertNotNull( idClassClass );
|
||||||
|
|
||||||
|
// Course should be interpreted as defining 3 attributes: `department`, `code` and `title`
|
||||||
|
assertEquals( 3, courseBinding.getAttributeBindingClosureSpan() );
|
||||||
|
|
||||||
|
// just make sure `title` is one of them
|
||||||
|
locateAttributeBinding( courseBinding, "title", BasicAttributeBinding.class );
|
||||||
|
|
||||||
|
BasicAttributeBinding deptAttribute = locateAttributeBinding(
|
||||||
|
courseBinding,
|
||||||
|
"department",
|
||||||
|
BasicAttributeBinding.class
|
||||||
|
);
|
||||||
|
assertEquals( 1, deptAttribute.getRelationalValueBindings().size() );
|
||||||
|
RelationalValueBinding deptColumnBinding = deptAttribute.getRelationalValueBindings().get( 0 );
|
||||||
|
org.hibernate.metamodel.spi.relational.Column deptColumn = assertTyping(
|
||||||
|
org.hibernate.metamodel.spi.relational.Column.class,
|
||||||
|
deptColumnBinding.getValue()
|
||||||
|
);
|
||||||
|
assertEquals( "dept", deptColumn.getColumnName().getText() );
|
||||||
|
|
||||||
|
BasicAttributeBinding codeAttribute = locateAttributeBinding(
|
||||||
|
courseBinding,
|
||||||
|
"code",
|
||||||
|
BasicAttributeBinding.class
|
||||||
|
);
|
||||||
|
RelationalValueBinding codeColumnBinding = codeAttribute.getRelationalValueBindings().get( 0 );
|
||||||
|
org.hibernate.metamodel.spi.relational.Column codeColumn = assertTyping(
|
||||||
|
org.hibernate.metamodel.spi.relational.Column.class,
|
||||||
|
codeColumnBinding.getValue()
|
||||||
|
);
|
||||||
|
assertEquals( "code", codeColumn.getColumnName().getText() );
|
||||||
|
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
courseBinding.getHierarchyDetails().getEntityIdentifier().isIdentifierAttributeBinding(
|
||||||
|
deptAttribute
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
courseBinding.getHierarchyDetails().getEntityIdentifier().isIdentifierAttributeBinding(
|
||||||
|
codeAttribute
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// get the virtual (non-aggregated composite) id attribute
|
||||||
|
EmbeddedAttributeBinding identifierAttribute = (EmbeddedAttributeBinding) courseBinding.getHierarchyDetails()
|
||||||
|
.getEntityIdentifier()
|
||||||
|
.getAttributeBinding();
|
||||||
|
assertNotNull( identifierAttribute );
|
||||||
|
// NOTE : assertSame() does `==`
|
||||||
|
|
||||||
|
EmbeddableBinding virtualEmbeddable = identifierAttribute.getEmbeddableBinding();
|
||||||
|
assertEquals( 2, virtualEmbeddable.attributeBindingSpan() );
|
||||||
|
|
||||||
|
for ( AttributeBinding subAttributeBinding : virtualEmbeddable.attributeBindings() ) {
|
||||||
|
assertTrue(
|
||||||
|
subAttributeBinding == deptAttribute
|
||||||
|
|| subAttributeBinding == codeAttribute
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue