HHH-7240 - Develop identifier handling in new metamodel

This commit is contained in:
Steve Ebersole 2012-04-11 15:59:11 -05:00
parent 2760c25a2c
commit 5b2cfd3c7c
11 changed files with 257 additions and 88 deletions

View File

@ -772,9 +772,10 @@ public class Binder {
}
private void bindSimpleIdentifier( final EntityBinding rootEntityBinding, final SimpleIdentifierSource identifierSource ) {
// locate the attribute binding
final BasicAttributeBinding idAttributeBinding =
( BasicAttributeBinding ) bindAttribute( rootEntityBinding, identifierSource.getIdentifierAttributeSource() );
rootEntityBinding.getHierarchyDetails().getEntityIdentifier().setValueBinding( idAttributeBinding );
// Configure ID generator
IdGenerator generator = identifierSource.getIdentifierGeneratorDescriptor();
if ( generator == null ) {
@ -782,14 +783,15 @@ public class Binder {
params.put( IdentifierGenerator.ENTITY_NAME, rootEntityBinding.getEntity().getName() );
generator = new IdGenerator( "default_assign_identity_generator", "assigned", params );
}
rootEntityBinding.getHierarchyDetails().getEntityIdentifier().setIdGenerator( generator );
rootEntityBinding.getHierarchyDetails().getEntityIdentifier().setUnsavedValue(
getIdentifierUnsavedValue( identifierSource, generator )
// determine the unsaved value mapping
final String unsavedValue = getIdentifierUnsavedValue( identifierSource, generator );
rootEntityBinding.getHierarchyDetails().getEntityIdentifier().bindAsSingleAttributeIdentifier(
idAttributeBinding,
generator,
unsavedValue
);
// Configure primary key in relational model
for ( final RelationalValueBinding valueBinding : idAttributeBinding.getRelationalValueBindings() ) {
rootEntityBinding.getPrimaryTable().getPrimaryKey().addColumn( ( Column ) valueBinding.getValue() );
}
}
private static String getIdentifierUnsavedValue(IdentifierSource identifierSource, IdGenerator generator) {
@ -845,9 +847,10 @@ public class Binder {
private void bindAggregatedCompositeIdentifier(
EntityBinding rootEntityBinding,
AggregatedCompositeIdentifierSource identifierSource) {
// locate the attribute binding
final CompositeAttributeBinding idAttributeBinding =
( CompositeAttributeBinding ) bindAttribute( rootEntityBinding, identifierSource.getIdentifierAttributeSource() );
rootEntityBinding.getHierarchyDetails().getEntityIdentifier().setValueBinding( idAttributeBinding );
// Configure ID generator
IdGenerator generator = identifierSource.getIdentifierGeneratorDescriptor();
if ( generator == null ) {
@ -855,20 +858,32 @@ public class Binder {
params.put( IdentifierGenerator.ENTITY_NAME, rootEntityBinding.getEntity().getName() );
generator = new IdGenerator( "default_assign_identity_generator", "assigned", params );
}
rootEntityBinding.getHierarchyDetails().getEntityIdentifier().setIdGenerator( generator );
rootEntityBinding.getHierarchyDetails().getEntityIdentifier().setUnsavedValue(
getIdentifierUnsavedValue( identifierSource, generator )
// determine the unsaved value mapping
final String unsavedValue = getIdentifierUnsavedValue( identifierSource, generator );
rootEntityBinding.getHierarchyDetails().getEntityIdentifier().bindAsSingleAttributeIdentifier(
idAttributeBinding,
generator,
unsavedValue
);
// Configure primary key in relational model
for ( final RelationalValueBinding valueBinding : idAttributeBinding.getRelationalValueBindings() ) {
rootEntityBinding.getPrimaryTable().getPrimaryKey().addColumn( ( Column ) valueBinding.getValue() );
}
}
private void bindNonAggregatedCompositeIdentifier(
EntityBinding rootEntityBinding,
NonAggregatedCompositeIdentifierSource identifierSource) {
throw new NotYetImplementedException( Nature.COMPOSITE.name() );
// locate the attribute bindings
List<SingularAttributeBinding> idAttributeBindings = new ArrayList<SingularAttributeBinding>();
for ( SingularAttributeSource attributeSource : identifierSource.getAttributeSourcesMakingUpIdentifier() ) {
idAttributeBindings.add(
(SingularAttributeBinding) bindAttribute( rootEntityBinding, attributeSource )
);
}
rootEntityBinding.getHierarchyDetails().getEntityIdentifier().bindAsMultipleAttributeIdentifier(
idAttributeBindings,
identifierSource.getLookupIdClass()
);
}
private void bindIndexedTablePrimaryKey( IndexedPluralAttributeBinding attributeBinding ) {

View File

@ -44,7 +44,8 @@ import org.hibernate.metamodel.spi.source.MetaAttributeContext;
* @author Steve Ebersole
*/
public class BasicAttributeBinding
extends AbstractSingularAttributeBinding {
extends AbstractSingularAttributeBinding
implements SingularNonAssociationAttributeBinding {
private final List<RelationalValueBinding> relationalValueBindings;
private boolean hasDerivedValue;
@ -99,6 +100,7 @@ public class BasicAttributeBinding
return generation;
}
@Override
public IdentifierGenerator createIdentifierGenerator(
IdGenerator idGenerator,
IdentifierGeneratorFactory identifierGeneratorFactory,

View File

@ -45,7 +45,7 @@ import org.hibernate.metamodel.spi.source.MetaAttributeContext;
*/
public class CompositeAttributeBinding
extends AbstractSingularAttributeBinding
implements AttributeBindingContainer {
implements SingularNonAssociationAttributeBinding, AttributeBindingContainer {
private final String path;
private final SingularAttribute parentReference;
private Map<String, AttributeBinding> attributeBindingMap = new HashMap<String, AttributeBinding>();

View File

@ -23,27 +23,37 @@
*/
package org.hibernate.metamodel.spi.binding;
import java.util.List;
import java.util.Properties;
import org.hibernate.AssertionFailure;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.factory.IdentifierGeneratorFactory;
import org.hibernate.metamodel.spi.relational.Column;
/**
* Binds the entity identifier.
* Hold information about the entity identifier. At a high-level, can be one of 2-types:<ul>
* <li>single-attribute identifier - this includes both simple identifiers and aggregated composite identifiers</li>
* <li>multiple-attribute identifier - non-aggregated composite identifiers</li>
* </ul>
*
* @author Steve Ebersole
* @author Hardy Ferentschik
*/
public class EntityIdentifier {
private final EntityBinding entityBinding;
private SingularAttributeBinding attributeBinding;
private IdentifierGenerator identifierGenerator;
private BoundType boundType;
private IdGenerator idGenerator;
private boolean isIdentifierMapper = false;
// todo : mappers, etc
private String unsavedValue;
private Class idClassClass; // the class named in @IdClass
private IdentifierGenerator identifierGenerator;
private SingularNonAssociationAttributeBinding attributeBinding;
private List<SingularAttributeBinding> nonAggregatedCompositeAttributeBindings;
/**
* Create an identifier
*
@ -53,32 +63,58 @@ public class EntityIdentifier {
this.entityBinding = entityBinding;
}
public SingularAttributeBinding getValueBinding() {
public void bindAsSingleAttributeIdentifier(
SingularNonAssociationAttributeBinding attributeBinding,
IdGenerator idGenerator,
String unsavedValue) {
if ( boundType != null ) {
throw new IllegalStateException( "Entity identifier was already bound" );
}
this.boundType = BoundType.SINGLE_ATTRIBUTE;
this.attributeBinding = attributeBinding;
this.idGenerator = idGenerator;
this.unsavedValue = unsavedValue;
// Configure primary key in relational model
for ( final RelationalValueBinding valueBinding : attributeBinding.getRelationalValueBindings() ) {
entityBinding.getPrimaryTable().getPrimaryKey().addColumn( (Column) valueBinding.getValue() );
}
}
public void bindAsMultipleAttributeIdentifier(
List<SingularAttributeBinding> nonAggregatedCompositeAttributeBindings,
Class idClassClass) {
if ( boundType != null ) {
throw new IllegalStateException( "Entity identifier was already bound" );
}
this.boundType = BoundType.MULTIPLE_ATTRIBUTE;
this.nonAggregatedCompositeAttributeBindings = nonAggregatedCompositeAttributeBindings;
this.idClassClass = idClassClass;
}
public SingularNonAssociationAttributeBinding getValueBinding() {
return attributeBinding;
}
public void setValueBinding(SingularAttributeBinding attributeBinding) {
if ( this.attributeBinding != null ) {
throw new AssertionFailure(
String.format(
"Identifier value binding already existed for %s",
entityBinding.getEntity().getName()
)
);
}
this.attributeBinding = attributeBinding;
public List<SingularAttributeBinding> getNonAggregatedCompositeAttributeBindings() {
return nonAggregatedCompositeAttributeBindings;
}
public void setIdGenerator(IdGenerator idGenerator) {
this.idGenerator = idGenerator;
public String getUnsavedValue() {
return unsavedValue;
}
public boolean isEmbedded() {
return attributeBinding.getRelationalValueBindings().size() > 1;
return boundType == BoundType.SINGLE_ATTRIBUTE && attributeBinding.getRelationalValueBindings().size() > 1;
}
public Class getIdClassClass() {
return idClassClass;
}
public boolean isIdentifierMapper() {
return isIdentifierMapper;
// i think
return boundType == BoundType.MULTIPLE_ATTRIBUTE && idClassClass != null;
}
// todo do we really need this createIdentifierGenerator and how do we make sure the getter is not called too early
@ -94,11 +130,8 @@ public class EntityIdentifier {
return identifierGenerator;
}
public String getUnsavedValue() {
return unsavedValue;
}
public void setUnsavedValue(String unsavedValue) {
this.unsavedValue = unsavedValue;
private static enum BoundType {
SINGLE_ATTRIBUTE,
MULTIPLE_ATTRIBUTE
}
}

View File

@ -103,14 +103,6 @@ public class ManyToOneAttributeBinding
return false;
}
@Override
public IdentifierGenerator createIdentifierGenerator(
IdGenerator idGenerator,
IdentifierGeneratorFactory factory,
Properties properties) {
return null;
}
@Override
public boolean isAssociation() {
return true;

View File

@ -28,7 +28,6 @@ import java.util.Properties;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.factory.IdentifierGeneratorFactory;
import org.hibernate.mapping.PropertyGeneration;
import org.hibernate.metamodel.spi.domain.SingularAttribute;
/**
@ -57,9 +56,4 @@ public interface SingularAttributeBinding extends AttributeBinding {
* @return {@code true} indicates that all values allow {@code null}; {@code false} indicates one or more do not
*/
public boolean isNullable();
/**
* Ugh
*/
public IdentifierGenerator createIdentifierGenerator(IdGenerator idGenerator, IdentifierGeneratorFactory factory, Properties properties);
}

View File

@ -0,0 +1,39 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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 java.util.Properties;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.factory.IdentifierGeneratorFactory;
/**
* @author Steve Ebersole
*/
public interface SingularNonAssociationAttributeBinding extends SingularAttributeBinding {
/**
* Ugh
*/
public IdentifierGenerator createIdentifierGenerator(IdGenerator idGenerator, IdentifierGeneratorFactory factory, Properties properties);
}

View File

@ -55,6 +55,7 @@ import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.BasicAttributeBinding;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
import org.hibernate.metamodel.spi.binding.SingularNonAssociationAttributeBinding;
import org.hibernate.metamodel.spi.domain.Attribute;
import org.hibernate.metamodel.spi.domain.Composite;
import org.hibernate.metamodel.spi.domain.SingularAttribute;
@ -389,7 +390,7 @@ public class EntityMetamodel implements Serializable {
boolean hasLazy = false;
// TODO: Fix after HHH-6337 is fixed; for now assume entityBinding is the root binding
SingularAttributeBinding rootEntityIdentifier = entityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding();
SingularNonAssociationAttributeBinding rootEntityIdentifier = entityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding();
// entityBinding.getAttributeClosureSpan() includes the identifier binding;
// "properties" here excludes the ID, so subtract 1 if the identifier binding is non-null
propertySpan = rootEntityIdentifier == null ?

View File

@ -61,31 +61,6 @@ import static org.junit.Assert.assertTrue;
public class AssertSourcesTest extends BaseUnitTestCase {
final ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().buildServiceRegistry() ;
@Test
public void testOrderEntitySources() {
MetadataSources ann = new MetadataSources( serviceRegistry );
ann.addAnnotatedClass( Order.class );
ann.addAnnotatedClass( Order.class );
ann.addAnnotatedClass( Order.OrderPk.class );
MetadataSourceProcessor annProcessor = new AnnotationMetadataSourceProcessorImpl( buildMetadata( ann ), ann );
testOrderEntitySources( annProcessor );
}
private void testOrderEntitySources(MetadataSourceProcessor processor) {
Iterator<EntityHierarchy> hierarchies = processor.extractEntityHierarchies().iterator();
assertTrue( hierarchies.hasNext() );
EntityHierarchy hierarchy = hierarchies.next();
assertFalse( hierarchies.hasNext() );
assertTrue( hierarchy.getHierarchyInheritanceType() == InheritanceType.NO_INHERITANCE );
RootEntitySource entitySource = hierarchy.getRootEntitySource();
assertFalse( entitySource.subclassEntitySources().iterator().hasNext() );
assertEquals( Order.class.getName(), entitySource.getClassName() );
assertEquals( Order.class.getName(), entitySource.getEntityName() );
assertNull( Order.class.getName(), entitySource.getJpaEntityName() );
}
@Test
public void testUserEntitySources() {
MetadataSources hbm = new MetadataSources( serviceRegistry );
@ -190,4 +165,54 @@ public class AssertSourcesTest extends BaseUnitTestCase {
}
@Test
public void testOrderEntitySources() {
MetadataSources ann = new MetadataSources( serviceRegistry );
ann.addAnnotatedClass( Order.class );
ann.addAnnotatedClass( Order.class );
ann.addAnnotatedClass( Order.OrderPk.class );
MetadataSourceProcessor annProcessor = new AnnotationMetadataSourceProcessorImpl( buildMetadata( ann ), ann );
testOrderEntitySources( annProcessor );
}
private void testOrderEntitySources(MetadataSourceProcessor processor) {
Iterator<EntityHierarchy> hierarchies = processor.extractEntityHierarchies().iterator();
assertTrue( hierarchies.hasNext() );
EntityHierarchy hierarchy = hierarchies.next();
assertFalse( hierarchies.hasNext() );
assertTrue( hierarchy.getHierarchyInheritanceType() == InheritanceType.NO_INHERITANCE );
RootEntitySource entitySource = hierarchy.getRootEntitySource();
assertFalse( entitySource.subclassEntitySources().iterator().hasNext() );
assertEquals( Order.class.getName(), entitySource.getClassName() );
assertEquals( Order.class.getName(), entitySource.getEntityName() );
assertNull( Order.class.getName(), entitySource.getJpaEntityName() );
}
@Test
public void testOrderNonAggregatedEntitySources() {
MetadataSources ann = new MetadataSources( serviceRegistry );
ann.addAnnotatedClass( Order.class );
ann.addAnnotatedClass( Order.class );
ann.addAnnotatedClass( Order.OrderPk.class );
MetadataSourceProcessor annProcessor = new AnnotationMetadataSourceProcessorImpl( buildMetadata( ann ), ann );
testOrderNonAggregatedEntitySources( annProcessor );
}
private void testOrderNonAggregatedEntitySources(MetadataSourceProcessor processor) {
Iterator<EntityHierarchy> hierarchies = processor.extractEntityHierarchies().iterator();
assertTrue( hierarchies.hasNext() );
EntityHierarchy hierarchy = hierarchies.next();
assertFalse( hierarchies.hasNext() );
assertTrue( hierarchy.getHierarchyInheritanceType() == InheritanceType.NO_INHERITANCE );
RootEntitySource entitySource = hierarchy.getRootEntitySource();
assertFalse( entitySource.subclassEntitySources().iterator().hasNext() );
assertEquals( Order.class.getName(), entitySource.getClassName() );
assertEquals( Order.class.getName(), entitySource.getEntityName() );
assertNull( Order.class.getName(), entitySource.getJpaEntityName() );
}
}

View File

@ -0,0 +1,64 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.internal.source;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
/**
* @author Steve Ebersole
*/
@Entity
@IdClass( Order.OrderPk.class )
public class OrderWithNonEmbeddedId {
private String customerIdentifier;
private int orderNumber;
public OrderWithNonEmbeddedId() {
}
public OrderWithNonEmbeddedId(String customerIdentifier, int orderNumber) {
this.customerIdentifier = customerIdentifier;
this.orderNumber = orderNumber;
}
@Id
public String getCustomerIdentifier() {
return customerIdentifier;
}
public void setCustomerIdentifier(String customerIdentifier) {
this.customerIdentifier = customerIdentifier;
}
@Id
public int getOrderNumber() {
return orderNumber;
}
public void setOrderNumber(int orderNumber) {
this.orderNumber = orderNumber;
}
}

View File

@ -25,6 +25,7 @@ package org.hibernate.metamodel.spi.binding;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
@ -91,8 +92,11 @@ public class SimpleValueBindingTests extends BaseUnitTestCase {
attributeBinding.getHibernateTypeDescriptor().setExplicitTypeName( "long" );
assertSame( idAttribute, attributeBinding.getAttribute() );
entityBinding.getHierarchyDetails().getEntityIdentifier().setValueBinding( attributeBinding );
//attributeBinding.setValue( idColumn );
entityBinding.getHierarchyDetails().getEntityIdentifier().bindAsSingleAttributeIdentifier(
attributeBinding,
new IdGenerator( "assigned", "assigned", Collections.<String,String>emptyMap() ),
"null"
);
}
Value<Class<?>> makeJavaType(final String name) {