From 997dd00880653e14b4a4d3a2c611e67f273f4ced Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Tue, 26 Apr 2011 10:37:28 -0700 Subject: [PATCH] HHH-6168 : Create an AttributeBinding for many-to-one and implement DomainState and RelationalState for HBM XML --- .../binding/AbstractAttributeBinding.java | 108 +++++++++++ .../metamodel/binding/AttributeBinding.java | 4 + .../metamodel/binding/EntityBinding.java | 30 +++- .../EntityReferencingAttributeBinding.java} | 21 +-- .../binding/ManyToOneAttributeBinding.java | 167 +++++++++++++++++ .../metamodel/binding/MappingDefaults.java | 1 + .../binding/PluralAttributeBinding.java | 7 - .../binding/SimpleAttributeBinding.java | 113 +----------- .../binding/SingularAttributeBinding.java | 20 ++- .../metamodel/relational/Column.java | 5 + .../source/hbm/AbstractEntityBinder.java | 87 +++++---- .../metamodel/source/hbm/HbmHelper.java | 7 +- .../source/hbm/HibernateMappingBinder.java | 2 +- .../AbstractHbmAttributeDomainState.java | 133 ++------------ .../HbmManyToOneAttributeDomainState.java | 168 ++++++++++++++++++ .../domain/HbmPluralAttributeDomainState.java | 57 ++++-- .../domain/HbmSimpleAttributeDomainState.java | 61 ++++++- .../relational/HbmColumnRelationalState.java | 30 +++- .../HbmDerivedValueRelationalState.java | 2 - .../HbmManyToOneRelationalStateContainer.java | 54 ++++++ ...bmSimpleValueRelationalStateContainer.java | 24 +++ .../internal/EntityReferenceResolver.java | 75 ++++++++ .../source/internal/MetadataImpl.java | 3 + 23 files changed, 855 insertions(+), 324 deletions(-) rename hibernate-core/src/main/java/org/hibernate/metamodel/{source/hbm/HibernateMappingJaxbRoot.java => binding/EntityReferencingAttributeBinding.java} (72%) create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/binding/ManyToOneAttributeBinding.java create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/domain/HbmManyToOneAttributeDomainState.java create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/relational/HbmManyToOneRelationalStateContainer.java create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/EntityReferenceResolver.java diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/AbstractAttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/AbstractAttributeBinding.java index aa2f7f2fc2..6bd127a3b0 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/AbstractAttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/AbstractAttributeBinding.java @@ -25,14 +25,19 @@ package org.hibernate.metamodel.binding; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; +import org.hibernate.MappingException; +import org.hibernate.cfg.NamingStrategy; import org.hibernate.metamodel.domain.Attribute; import org.hibernate.metamodel.domain.MetaAttribute; import org.hibernate.metamodel.relational.Column; import org.hibernate.metamodel.relational.DerivedValue; import org.hibernate.metamodel.relational.SimpleValue; +import org.hibernate.metamodel.relational.Size; import org.hibernate.metamodel.relational.TableSpecification; import org.hibernate.metamodel.relational.Tuple; import org.hibernate.metamodel.relational.Value; @@ -57,6 +62,8 @@ public abstract class AbstractAttributeBinding implements AttributeBinding { private final HibernateTypeDescriptor hibernateTypeDescriptor = new HibernateTypeDescriptor(); private final EntityBinding entityBinding; + private final Set entityReferencingAttributeBindings = + new HashSet(); private Attribute attribute; private Value value; @@ -102,6 +109,72 @@ public abstract class AbstractAttributeBinding implements AttributeBinding { this.attribute = attribute; } + protected void initializeColumnValue(ColumnRelationalState state, boolean forceNonNullable, boolean forceUnique) { + Column columnValue = createColumn( state, forceNonNullable, forceUnique ); + setValue( columnValue ); + } + + private Column createColumn(ColumnRelationalState state, boolean forceNonNullable, boolean forceUnique) { + final String explicitName = state.getExplicitColumnName(); + final String logicalColumnName = state.getNamingStrategy().logicalColumnName( explicitName, getAttribute().getName() ); + final TableSpecification table = getEntityBinding().getBaseTable(); + final String columnName = + explicitName == null ? + state.getNamingStrategy().propertyToColumnName( getAttribute().getName() ) : + state.getNamingStrategy().columnName( explicitName ); +// todo : find out the purpose of these logical bindings +// mappings.addColumnBinding( logicalColumnName, column, table ); + Column columnValue = table.createColumn( columnName ); + columnValue.getSize().initialize( state.getSize() ); + columnValue.setNullable( ! forceNonNullable && state.isNullable() ); + columnValue.setUnique( ! forceUnique && state.isUnique() ); + columnValue.setCheckCondition( state.getCheckCondition() ); + columnValue.setDefaultValue( state.getDefault() ); + columnValue.setSqlType( state.getSqlType() ); + columnValue.setWriteFragment( state.getCustomWriteFragment() ); + columnValue.setReadFragment( state.getCustomReadFragment() ); + columnValue.setComment( state.getComment() ); + for ( String uniqueKey : state.getUniqueKeys() ) { + table.getOrCreateUniqueKey( uniqueKey ).addColumn( columnValue ); + } + for ( String index : state.getIndexes() ) { + table.getOrCreateIndex( index ).addColumn( columnValue ); + } + return columnValue; + } + + public final void initializeDerivedValue(T state) { + value = createDerivedValue( state ); + } + + private DerivedValue createDerivedValue(DerivedRelationalState state) { + return getEntityBinding().getBaseTable().createDerivedValue( state.getFormula() ); + } + + public final void initializeSingleValue(SingleValueRelationalState state, boolean forceNonNullable, boolean forceUnique) { + value = createSingleValue( state, forceNonNullable, forceUnique ); + } + + protected SimpleValue createSingleValue(SingleValueRelationalState state, boolean forceNonNullable, boolean forceUnique) { + if ( state instanceof ColumnRelationalState ) { + return createColumn( ColumnRelationalState.class.cast( state ), forceNonNullable, forceUnique ); + } + else if ( state instanceof DerivedRelationalState ) { + return createDerivedValue( DerivedRelationalState.class.cast( state ) ); + } + else { + throw new MappingException( "unknown relational state:" + state.getClass().getName() ); + } + } + + protected final void initializeTupleValue(Set singleValueStates, boolean forceNonNullable, boolean forceUnique) { + Tuple tuple = getEntityBinding().getBaseTable().createTuple( "[" + getAttribute().getName() + "]" ); + for ( SingleValueRelationalState singleValueState : singleValueStates ) { + tuple.addValue( createSingleValue( singleValueState, forceNonNullable, forceUnique ) ); + } + value = tuple; + } + @Override public Value getValue() { return value; @@ -212,4 +285,39 @@ public abstract class AbstractAttributeBinding implements AttributeBinding { protected void setLazy(boolean isLazy) { this.isLazy = isLazy; } + + public void addEntityReferencingAttributeBinding(EntityReferencingAttributeBinding referencingAttributeBinding) { + entityReferencingAttributeBindings.add( referencingAttributeBinding ); + } + + public void validate() { + if ( ! entityReferencingAttributeBindings.isEmpty() ) { + // TODO; validate that this AttributeBinding can be a target of an entity reference + // (e.g., this attribute is the primary key or there is a unique-key) + // can a unique attribute be used as a target? if so, does it need to be non-null? + } + } + + public static interface SingleValueRelationalState {} + + public static interface ColumnRelationalState extends SimpleAttributeBinding.SingleValueRelationalState { + NamingStrategy getNamingStrategy(); + String getExplicitColumnName(); + boolean isUnique(); + Size getSize(); + boolean isNullable(); + String getCheckCondition(); + String getDefault(); + String getSqlType(); + String getCustomWriteFragment(); + String getCustomReadFragment(); + String getComment(); + Set getUniqueKeys(); + Set getIndexes(); + } + + public static interface DerivedRelationalState extends SingleValueRelationalState { + String getFormula(); + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/AttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/AttributeBinding.java index 266b656052..572e62558d 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/AttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/AttributeBinding.java @@ -102,4 +102,8 @@ public interface AttributeBinding { public boolean[] getColumnInsertability(); public boolean isSimpleValue(); public boolean isLazy(); + + public void addEntityReferencingAttributeBinding(EntityReferencingAttributeBinding attributeBinding); + + public void validate(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/EntityBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/EntityBinding.java index 7f176a0e1e..35c1989eb4 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/EntityBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/EntityBinding.java @@ -25,8 +25,11 @@ package org.hibernate.metamodel.binding; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import org.hibernate.MappingException; import org.hibernate.engine.Versioning; @@ -41,6 +44,7 @@ import org.hibernate.metamodel.source.hbm.xml.mapping.XMLSqlDeleteElement; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLSqlInsertElement; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLSqlUpdateElement; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLSynchronizeElement; +import org.hibernate.metamodel.source.spi.MetadataImplementor; import org.hibernate.metamodel.source.util.MappingHelper; /** @@ -57,6 +61,8 @@ public class EntityBinding { private TableSpecification baseTable; private Map attributeBindingMap = new HashMap(); + private Set entityReferencingAttributeBindings = + new HashSet(); private Caching caching; @@ -222,6 +228,10 @@ public class EntityBinding { return attributeBindingMap.get( name ); } + public Iterable getEntityReferencingAttributeBindings() { + return entityReferencingAttributeBindings; + } + public SimpleAttributeBinding makeSimplePrimaryKeyAttributeBinding(String name) { final SimpleAttributeBinding binding = makeSimpleAttributeBinding( name, true, true ); getEntityIdentifier().setValueBinding( binding ); @@ -250,18 +260,34 @@ public class EntityBinding { private SimpleAttributeBinding makeSimpleAttributeBinding(String name, boolean forceNonNullable, boolean forceUnique) { final SimpleAttributeBinding binding = new SimpleAttributeBinding( this, forceNonNullable, forceUnique ); - attributeBindingMap.put( name, binding ); + registerAttributeBinding( name, binding ); + binding.setAttribute( entity.getAttribute( name ) ); + return binding; + } + + public ManyToOneAttributeBinding makeManyToOneAttributeBinding(String name) { + final ManyToOneAttributeBinding binding = new ManyToOneAttributeBinding( this ); + registerAttributeBinding( name, binding ); binding.setAttribute( entity.getAttribute( name ) ); return binding; } public BagBinding makeBagAttributeBinding(String name) { final BagBinding binding = new BagBinding( this ); - attributeBindingMap.put( name, binding ); + registerAttributeBinding( name, binding ); binding.setAttribute( entity.getAttribute( name ) ); return binding; } + private void registerAttributeBinding(String name, EntityReferencingAttributeBinding attributeBinding) { + entityReferencingAttributeBindings.add( attributeBinding ); + registerAttributeBinding( name, (AttributeBinding) attributeBinding ); + } + + private void registerAttributeBinding(String name, AttributeBinding attributeBinding) { + attributeBindingMap.put( name, attributeBinding ); + } + public Caching getCaching() { return caching; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/HibernateMappingJaxbRoot.java b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/EntityReferencingAttributeBinding.java similarity index 72% rename from hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/HibernateMappingJaxbRoot.java rename to hibernate-core/src/main/java/org/hibernate/metamodel/binding/EntityReferencingAttributeBinding.java index 3427157a40..412da6d74a 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/HibernateMappingJaxbRoot.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/EntityReferencingAttributeBinding.java @@ -21,18 +21,19 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.metamodel.source.hbm; +package org.hibernate.metamodel.binding; -import org.hibernate.metamodel.source.Origin; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping; -import org.hibernate.metamodel.source.internal.JaxbRoot; +import org.hibernate.metamodel.relational.Value; /** + * TODO : javadoc + * * @author Gail Badner */ -public class HibernateMappingJaxbRoot extends JaxbRoot { - - public HibernateMappingJaxbRoot(XMLHibernateMapping root, Origin origin) { - super(root, origin); - } -} +public interface EntityReferencingAttributeBinding extends AttributeBinding { + boolean isReferenceResolved(); + String getReferencedEntityName(); + String getReferencedAttributeName(); + EntityBinding getReferencedEntityBinding(); + void resolveReference(AttributeBinding attributeBinding); +} \ No newline at end of file diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/ManyToOneAttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/ManyToOneAttributeBinding.java new file mode 100644 index 0000000000..f8934e71d8 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/ManyToOneAttributeBinding.java @@ -0,0 +1,167 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, 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.binding; + +import java.util.Iterator; + +import org.hibernate.MappingException; +import org.hibernate.metamodel.relational.ForeignKey; +import org.hibernate.metamodel.relational.SimpleValue; +import org.hibernate.metamodel.relational.Column; +import org.hibernate.metamodel.source.Metadata; + +/** + * TODO : javadoc + * + * @author Gail Badner + */ +public class ManyToOneAttributeBinding extends SingularAttributeBinding implements EntityReferencingAttributeBinding { + private boolean isLogicalOneToOne; + private boolean isPropertyReference; + private String foreignKeyName; + private String referencedAttributeName; + private String referencedEntityName; + private AttributeBinding referencedAttributeBinding; + private boolean ignoreNotFound; + + public static interface DomainState extends SingularAttributeBinding.DomainState { + boolean isUnwrapProxy(); + String getReferencedAttributeName(); + String getReferencedEntityName(); + boolean ignoreNotFound(); + } + + public static interface RelationalState extends SingleValueRelationalState { + boolean isLogicalOneToOne(); + String getForeignKeyName(); + } + + ManyToOneAttributeBinding(EntityBinding entityBinding) { + super( entityBinding, false, false ); + } + + public final void initialize(DomainState state) { + super.initialize( state ); + isPropertyReference = state.getReferencedAttributeName() != null; + referencedAttributeName = state.getReferencedAttributeName(); + referencedEntityName = state.getReferencedEntityName(); + } + + public final void initialize(RelationalState state) { + super.initializeSingleValue( state ); + isLogicalOneToOne = state.isLogicalOneToOne(); + foreignKeyName = state.getForeignKeyName(); + } + + public final String getReferencedEntityName() { + return referencedEntityName; + } + + public final String getReferencedAttributeName() { + if ( referencedAttributeName == null ) { + throw new IllegalStateException( + "Referenced attribute name is not available." + ); + } + return referencedAttributeName; + } + + public final boolean isReferenceResolved() { + return referencedAttributeBinding != null; + } + + public final EntityBinding getReferencedEntityBinding() { + if ( ! isReferenceResolved() ) { + throw new IllegalStateException( "EntityBinding reference has not be referenced." ); + } + // TODO: throw exception if referencedEntityBinding is null? + return referencedAttributeBinding.getEntityBinding(); + } + + public final void resolveReference(AttributeBinding referencedAttributeBinding) { + if ( ! referencedEntityName.equals( referencedAttributeBinding.getEntityBinding().getEntity().getName() ) ) { + throw new IllegalStateException( + "attempt to set EntityBinding with name: [" + + referencedAttributeBinding.getEntityBinding().getEntity().getName() + + "; entity name should be: " + referencedEntityName + ); + } + if ( referencedAttributeName == null ) { + referencedAttributeName = referencedAttributeBinding.getAttribute().getName(); + } + else if ( ! referencedAttributeName.equals( referencedAttributeBinding.getAttribute().getName() ) ) { + throw new IllegalStateException( + "Inconsistent attribute name; expected: " + referencedAttributeName + + "actual: " + referencedAttributeBinding.getAttribute().getName() + ); + } + this.referencedAttributeBinding = referencedAttributeBinding; + buildForeignKey(); + } + + private void buildForeignKey() { + // TODO: move this stuff to relational model + ForeignKey foreignKey = getTable().createForeignKey( referencedAttributeBinding.getTable(), foreignKeyName ); + Iterator referencingValueIterator = getValues().iterator(); + Iterator targetValueIterator = referencedAttributeBinding.getValues().iterator(); + while ( referencingValueIterator.hasNext() ) { + if ( ! targetValueIterator.hasNext() ) { + // TODO: improve this message + throw new MappingException( "number of values in many-to-one reference is greater than number of values in target" ); + } + SimpleValue referencingValue = referencingValueIterator.next(); + SimpleValue targetValue = targetValueIterator.next(); + if ( Column.class.isInstance( referencingValue ) ) { + if ( ! Column.class.isInstance( targetValue ) ) { + // TODO improve this message + throw new MappingException( "referencing value is a column, but target is not a column" ); + } + foreignKey.addColumnMapping( Column.class.cast( referencingValue ), Column.class.cast( targetValue ) ); + } + else if ( Column.class.isInstance( targetValue ) ) { + // TODO: improve this message + throw new MappingException( "referencing value is not a column, but target is a column." ); + } + } + if ( targetValueIterator.hasNext() ) { + throw new MappingException( "target value has more simple values than referencing value" ); + } + } + + public boolean isSimpleValue() { + return false; + } + + public void validate() { + // can't check this until both the domain and relational states are initialized... + if ( getCascade() != null && getCascade().indexOf( "delete-orphan" ) >= 0 ) { + if ( ! isLogicalOneToOne ) { + throw new MappingException( + "many-to-one attribute [" + getAttribute().getName() + "] does not support orphan delete as it is not unique" + ); + } + } + //TODO: validate that the entity reference is resolved + } +} \ No newline at end of file diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/MappingDefaults.java b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/MappingDefaults.java index db0bb147f6..8f18a0978d 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/MappingDefaults.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/MappingDefaults.java @@ -33,6 +33,7 @@ import org.hibernate.metamodel.domain.MetaAttribute; */ public interface MappingDefaults { Map getMappingMetas(); + String getPackageName(); String getDefaultSchemaName(); String getDefaultCatalogName(); String getDefaultCascade(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/PluralAttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/PluralAttributeBinding.java index 08b28f6113..9d597057f4 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/PluralAttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/PluralAttributeBinding.java @@ -67,7 +67,6 @@ public abstract class PluralAttributeBinding extends AbstractAttributeBinding { boolean isEmbedded(); boolean isOptimisticLocked(); Class getCollectionPersisterClass(); - String getTypeName(); java.util.Map getFilters(); java.util.Set getSynchronizedTables(); CustomSQL getCustomSQLInsert(); @@ -105,7 +104,6 @@ public abstract class PluralAttributeBinding extends AbstractAttributeBinding { private boolean embedded = true; private boolean optimisticLocked = true; private Class collectionPersisterClass; - private String typeName; private final java.util.Map filters = new HashMap(); private final java.util.Set synchronizedTables = new HashSet(); @@ -145,7 +143,6 @@ public abstract class PluralAttributeBinding extends AbstractAttributeBinding { embedded = state.isEmbedded(); optimisticLocked = state.isOptimisticLocked(); collectionPersisterClass = state.getCollectionPersisterClass(); - typeName = state.getTypeName(); filters.putAll( state.getFilters() ); synchronizedTables.addAll( state.getSynchronizedTables() ); customSQLInsert = state.getCustomSQLInsert(); @@ -257,10 +254,6 @@ public abstract class PluralAttributeBinding extends AbstractAttributeBinding { return collectionPersisterClass; } - public String getTypeName() { - return typeName; - } - public void addFilter(String name, String condition) { filters.put( name, condition ); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/SimpleAttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/SimpleAttributeBinding.java index 4c76cd715d..f11cf2680f 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/SimpleAttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/SimpleAttributeBinding.java @@ -26,12 +26,10 @@ package org.hibernate.metamodel.binding; import java.util.Set; import org.hibernate.MappingException; -import org.hibernate.cfg.NamingStrategy; import org.hibernate.mapping.PropertyGeneration; import org.hibernate.metamodel.relational.Column; import org.hibernate.metamodel.relational.DerivedValue; import org.hibernate.metamodel.relational.SimpleValue; -import org.hibernate.metamodel.relational.Size; import org.hibernate.metamodel.relational.TableSpecification; import org.hibernate.metamodel.relational.Tuple; @@ -45,45 +43,6 @@ public class SimpleAttributeBinding extends SingularAttributeBinding { public PropertyGeneration getPropertyGeneration(); } - public static interface SingleValueRelationalState { - } - - public static interface ColumnRelationalState extends SingleValueRelationalState { - NamingStrategy getNamingStrategy(); - - String getExplicitColumnName(); - - boolean isUnique(); - - Size getSize(); - - boolean isNullable(); - - String getCheckCondition(); - - String getDefault(); - - String getSqlType(); - - String getCustomWriteFragment(); - - String getCustomReadFragment(); - - String getComment(); - - Set getUniqueKeys(); - - Set getIndexes(); - } - - public static interface DerivedRelationalState extends SingleValueRelationalState { - String getFormula(); - } - - public static interface TupleRelationalState { - Set getSingleValueRelationalStates(); - } - private PropertyGeneration generation; SimpleAttributeBinding(EntityBinding entityBinding, boolean forceNonNullable, boolean forceUnique) { @@ -95,80 +54,20 @@ public class SimpleAttributeBinding extends SingularAttributeBinding { generation = state.getPropertyGeneration(); } - public final void initializeColumnValue(ColumnRelationalState state) { - Column columnValue = createColumn( state ); - setValue( columnValue ); - } - - private Column createColumn(ColumnRelationalState state) { - final String explicitName = state.getExplicitColumnName(); - final String logicalColumnName = state.getNamingStrategy() - .logicalColumnName( explicitName, getAttribute().getName() ); - final TableSpecification table = getEntityBinding().getBaseTable(); - final String columnName = - explicitName == null ? - state.getNamingStrategy().propertyToColumnName( getAttribute().getName() ) : - state.getNamingStrategy().columnName( explicitName ); -// todo : find out the purpose of these logical bindings -// mappings.addColumnBinding( logicalColumnName, column, table ); - Column columnValue = table.createColumn( columnName ); - columnValue.getSize().initialize( state.getSize() ); - columnValue.setNullable( !forceNonNullable() && state.isNullable() ); - columnValue.setUnique( !forceUnique() && state.isUnique() ); - columnValue.setCheckCondition( state.getCheckCondition() ); - columnValue.setDefaultValue( state.getDefault() ); - columnValue.setSqlType( state.getSqlType() ); - columnValue.setWriteFragment( state.getCustomWriteFragment() ); - columnValue.setReadFragment( state.getCustomReadFragment() ); - columnValue.setComment( state.getComment() ); - for ( String uniqueKey : state.getUniqueKeys() ) { - table.getOrCreateUniqueKey( uniqueKey ).addColumn( columnValue ); - } - for ( String index : state.getIndexes() ) { - table.getOrCreateIndex( index ).addColumn( columnValue ); - } - return columnValue; - } - - private boolean isUnique(ColumnRelationalState state) { - return isPrimaryKey() || state.isUnique(); - - } - - public final void initializeDerivedValue(T state) { - setValue( createDerivedValue( state ) ); - } - - private DerivedValue createDerivedValue(DerivedRelationalState state) { - return getEntityBinding().getBaseTable().createDerivedValue( state.getFormula() ); - } - public final void initializeTupleValue(TupleRelationalState state) { if ( state.getSingleValueRelationalStates().size() == 0 ) { throw new MappingException( "Tuple state does not contain any values." ); } if ( state.getSingleValueRelationalStates().size() == 1 ) { - setValue( createSingleValue( state.getSingleValueRelationalStates().iterator().next() ) ); + initializeSingleValue( state.getSingleValueRelationalStates().iterator().next() ); } else { - Tuple tuple = getEntityBinding().getBaseTable().createTuple( "[" + getAttribute().getName() + "]" ); - for ( SingleValueRelationalState singleValueState : state.getSingleValueRelationalStates() ) { - tuple.addValue( createSingleValue( singleValueState ) ); - } - setValue( tuple ); + initializeTupleValue( state.getSingleValueRelationalStates() ); } } - private SimpleValue createSingleValue(SingleValueRelationalState state) { - if ( state instanceof ColumnRelationalState ) { - return createColumn( ColumnRelationalState.class.cast( state ) ); - } - else if ( state instanceof DerivedRelationalState ) { - return createDerivedValue( DerivedRelationalState.class.cast( state ) ); - } - else { - throw new MappingException( "unknown relational state:" + state.getClass().getName() ); - } + private boolean isUnique(ColumnRelationalState state) { + return isPrimaryKey() || state.isUnique(); } @Override @@ -183,4 +82,8 @@ public class SimpleAttributeBinding extends SingularAttributeBinding { public PropertyGeneration getGeneration() { return generation; } + + public static interface TupleRelationalState { + Set getSingleValueRelationalStates(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/SingularAttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/SingularAttributeBinding.java index 62c314c467..c2d4794ebc 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/SingularAttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/SingularAttributeBinding.java @@ -23,10 +23,12 @@ */ package org.hibernate.metamodel.binding; -import org.dom4j.Element; +import java.util.Set; -import org.hibernate.metamodel.domain.Attribute; -import org.hibernate.metamodel.source.util.DomHelper; +import org.hibernate.MappingException; +import org.hibernate.metamodel.relational.DerivedValue; +import org.hibernate.metamodel.relational.SimpleValue; +import org.hibernate.metamodel.relational.Tuple; /** * TODO : javadoc @@ -62,6 +64,18 @@ public abstract class SingularAttributeBinding extends AbstractAttributeBinding unsavedValue = state.getUnsavedValue(); } + public final void initializeColumnValue(ColumnRelationalState state) { + initializeColumnValue( state, forceNonNullable, forceUnique ); + } + + public final void initializeSingleValue(SingleValueRelationalState state) { + initializeSingleValue( state, forceNonNullable, forceUnique ); + } + + protected void initializeTupleValue(Set singleValueStates) { + initializeTupleValue( singleValueStates, forceNonNullable, forceUnique ); + } + public boolean isInsertable() { return insertable; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/relational/Column.java b/hibernate-core/src/main/java/org/hibernate/metamodel/relational/Column.java index 4b6128abcc..b5e56f488e 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/relational/Column.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/relational/Column.java @@ -23,6 +23,11 @@ */ package org.hibernate.metamodel.relational; +import java.util.Set; + +import org.hibernate.cfg.NamingStrategy; +import org.hibernate.metamodel.binding.SimpleAttributeBinding; + /** * Models a physical column * diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/AbstractEntityBinder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/AbstractEntityBinder.java index a7ab3d84c0..64de6d27d6 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/AbstractEntityBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/AbstractEntityBinder.java @@ -37,6 +37,7 @@ import org.hibernate.internal.util.StringHelper; import org.hibernate.metamodel.binding.AttributeBinding; import org.hibernate.metamodel.binding.BagBinding; import org.hibernate.metamodel.binding.EntityBinding; +import org.hibernate.metamodel.binding.ManyToOneAttributeBinding; import org.hibernate.metamodel.binding.PluralAttributeBinding; import org.hibernate.metamodel.binding.SimpleAttributeBinding; import org.hibernate.metamodel.domain.Entity; @@ -47,36 +48,13 @@ import org.hibernate.metamodel.relational.Schema; import org.hibernate.metamodel.relational.Table; import org.hibernate.metamodel.relational.TableSpecification; import org.hibernate.metamodel.relational.UniqueKey; +import org.hibernate.metamodel.source.hbm.state.domain.HbmManyToOneAttributeDomainState; +import org.hibernate.metamodel.source.hbm.state.relational.HbmManyToOneRelationalStateContainer; +import org.hibernate.metamodel.source.hbm.xml.mapping.*; import org.hibernate.metamodel.source.internal.MetadataImpl; import org.hibernate.metamodel.source.hbm.state.domain.HbmPluralAttributeDomainState; import org.hibernate.metamodel.source.hbm.state.domain.HbmSimpleAttributeDomainState; import org.hibernate.metamodel.source.hbm.state.relational.HbmSimpleValueRelationalStateContainer; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLAnyElement; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLBagElement; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLComponentElement; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLDynamicComponentElement; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLFilterElement; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping.XMLClass; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping.XMLClass.XMLDiscriminator; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping.XMLClass.XMLId; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping.XMLClass.XMLTimestamp; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping.XMLClass.XMLVersion; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLIdbagElement; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLJoinElement; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLJoinedSubclassElement; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLListElement; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLManyToOneElement; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLMapElement; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLOneToOneElement; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLPropertiesElement; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLPropertyElement; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLQueryElement; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLResultsetElement; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLSetElement; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLSqlQueryElement; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLSubclassElement; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLTuplizerElement; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLUnionSubclassElement; /** * TODO : javadoc @@ -88,7 +66,7 @@ abstract class AbstractEntityBinder { private final Schema.Name schemaName; AbstractEntityBinder(HibernateMappingBinder hibernateMappingBinder, - XMLClass entityClazz) { + XMLHibernateMapping.XMLClass entityClazz) { this.hibernateMappingBinder = hibernateMappingBinder; this.schemaName = new Schema.Name( ( entityClazz.getSchema() == null ? @@ -119,7 +97,7 @@ abstract class AbstractEntityBinder { return getMetadata().getNamingStrategy(); } - protected void basicEntityBinding(XMLClass entityClazz, + protected void basicEntityBinding(XMLHibernateMapping.XMLClass entityClazz, EntityBinding entityBinding, Hierarchical superType) { entityBinding.fromHbmXml( @@ -151,7 +129,7 @@ abstract class AbstractEntityBinder { return hibernateMappingBinder.getDefaultAccess(); } - private void bindPojoRepresentation(XMLClass entityClazz, + private void bindPojoRepresentation(XMLHibernateMapping.XMLClass entityClazz, EntityBinding entityBinding) { String className = hibernateMappingBinder.getClassName( entityClazz.getName() ); String proxyName = hibernateMappingBinder.getClassName( entityClazz.getProxy() ); @@ -172,7 +150,7 @@ abstract class AbstractEntityBinder { } } - private void bindDom4jRepresentation(XMLClass entityClazz, + private void bindDom4jRepresentation(XMLHibernateMapping.XMLClass entityClazz, EntityBinding entityBinding) { String nodeName = entityClazz.getNode(); if ( nodeName == null ) { @@ -186,7 +164,7 @@ abstract class AbstractEntityBinder { } } - private void bindMapRepresentation(XMLClass entityClazz, + private void bindMapRepresentation(XMLHibernateMapping.XMLClass entityClazz, EntityBinding entityBinding) { XMLTuplizerElement tuplizer = locateTuplizerDefinition( entityClazz, EntityMode.MAP ); if ( tuplizer != null ) { @@ -202,7 +180,7 @@ abstract class AbstractEntityBinder { * * @return The tuplizer element, or null. */ - private static XMLTuplizerElement locateTuplizerDefinition(XMLClass container, + private static XMLTuplizerElement locateTuplizerDefinition(XMLHibernateMapping.XMLClass container, EntityMode entityMode) { for ( XMLTuplizerElement tuplizer : container.getTuplizer() ) { if ( entityMode.toString().equals( tuplizer.getEntityMode() ) ) { @@ -235,7 +213,7 @@ abstract class AbstractEntityBinder { } protected String getClassTableName( - XMLClass entityClazz, + XMLHibernateMapping.XMLClass entityClazz, EntityBinding entityBinding, Table denormalizedSuperTable) { final String entityName = entityBinding.getEntity().getName(); @@ -254,7 +232,7 @@ abstract class AbstractEntityBinder { return physicalTableName; } - protected void buildAttributeBindings(XMLClass entityClazz, + protected void buildAttributeBindings(XMLHibernateMapping.XMLClass entityClazz, EntityBinding entityBinding) { // null = UniqueKey (we are not binding a natural-id mapping) // true = mutable, by default properties are mutable @@ -273,7 +251,7 @@ abstract class AbstractEntityBinder { * @param nullable */ protected void buildAttributeBindings( - XMLClass entityClazz, + XMLHibernateMapping.XMLClass entityClazz, EntityBinding entityBinding, UniqueKey uniqueKey, boolean mutable, @@ -323,6 +301,10 @@ abstract class AbstractEntityBinder { //hibernateMappingBinder.getHibernateXmlBinder().getMetadata().addCollection( attributeBinding ); } else if ( XMLManyToOneElement.class.isInstance( attribute ) ) { + XMLManyToOneElement manyToOne = XMLManyToOneElement.class.cast( attribute ); + ManyToOneAttributeBinding manyToOneBinding = entityBinding.makeManyToOneAttributeBinding( manyToOne.getName() ); + bindManyToOne( manyToOne, manyToOneBinding, entityBinding ); + attributeBinding = manyToOneBinding; // todo : implement // value = new ManyToOne( mappings, table ); // bindManyToOne( subElement, (ManyToOne) value, propertyName, nullable, mappings ); @@ -440,7 +422,7 @@ PrimitiveArray } - protected void bindSimpleAttribute(XMLId id, + protected void bindSimpleAttribute(XMLHibernateMapping.XMLClass.XMLId id, SimpleAttributeBinding attributeBinding, EntityBinding entityBinding, String attributeName) { @@ -468,7 +450,7 @@ PrimitiveArray } } - protected void bindSimpleAttribute(XMLDiscriminator discriminator, + protected void bindSimpleAttribute(XMLHibernateMapping.XMLClass.XMLDiscriminator discriminator, SimpleAttributeBinding attributeBinding, EntityBinding entityBinding, String attributeName) { @@ -496,7 +478,7 @@ PrimitiveArray } } - protected void bindSimpleAttribute(XMLVersion version, + protected void bindSimpleAttribute(XMLHibernateMapping.XMLClass.XMLVersion version, SimpleAttributeBinding attributeBinding, EntityBinding entityBinding, String attributeName) { @@ -524,7 +506,7 @@ PrimitiveArray } } - protected void bindSimpleAttribute(XMLTimestamp timestamp, + protected void bindSimpleAttribute(XMLHibernateMapping.XMLClass.XMLTimestamp timestamp, SimpleAttributeBinding attributeBinding, EntityBinding entityBinding, String attributeName) { @@ -603,6 +585,33 @@ PrimitiveArray } } + private void bindManyToOne(XMLManyToOneElement manyToOne, + ManyToOneAttributeBinding attributeBinding, + EntityBinding entityBinding) { + if ( attributeBinding.getAttribute() == null ) { + attributeBinding.initialize( + new HbmManyToOneAttributeDomainState( + hibernateMappingBinder, + entityBinding.getEntity().getOrCreateSingularAttribute( manyToOne.getName() ), + entityBinding.getMetaAttributes(), + manyToOne + ) + ); + } + + if ( attributeBinding.getValue() == null ) { + // relational model has not been bound yet + // boolean (true here) indicates that by default column names should be guessed + attributeBinding.initialize( + new HbmManyToOneRelationalStateContainer( + getHibernateMappingBinder(), + true, + manyToOne + ) + ); + } + } + // private static Property createProperty( // final Value value, // final String propertyName, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/HbmHelper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/HbmHelper.java index 7e0700507c..437c095eac 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/HbmHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/HbmHelper.java @@ -95,8 +95,11 @@ public class HbmHelper { } public static String extractEntityName( XMLClass entityClazz, String unqualifiedPackageName) { - String entityName = entityClazz.getEntityName(); - return entityName == null ? getClassName( entityClazz.getName(), unqualifiedPackageName ) : entityName; + return extractEntityName( entityClazz.getEntityName(), entityClazz.getName(), unqualifiedPackageName ); + } + + public static String extractEntityName( String entityName, String entityClassName, String unqualifiedPackageName) { + return entityName == null ? getClassName( entityClassName, unqualifiedPackageName ) : entityName; } public static String getClassName(Attribute att, String unqualifiedPackageName) { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/HibernateMappingBinder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/HibernateMappingBinder.java index 405a5e4499..e0b8f85d01 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/HibernateMappingBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/HibernateMappingBinder.java @@ -119,7 +119,7 @@ class HibernateMappingBinder implements MappingDefaults { return hibernateXmlBinder.getMetadata().getNamingStrategy(); } - String getPackageName() { + public String getPackageName() { return packageName; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/domain/AbstractHbmAttributeDomainState.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/domain/AbstractHbmAttributeDomainState.java index 54929f1f78..096b27d9dd 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/domain/AbstractHbmAttributeDomainState.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/domain/AbstractHbmAttributeDomainState.java @@ -27,17 +27,9 @@ import java.util.Map; import org.hibernate.metamodel.binding.AbstractAttributeBinding; import org.hibernate.metamodel.binding.EntityBinding; -import org.hibernate.metamodel.binding.HibernateTypeDescriptor; import org.hibernate.metamodel.binding.MappingDefaults; import org.hibernate.metamodel.domain.Attribute; import org.hibernate.metamodel.domain.MetaAttribute; -import org.hibernate.metamodel.source.hbm.HbmHelper; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLBagElement; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping.XMLClass.XMLDiscriminator; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping.XMLClass.XMLId; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping.XMLClass.XMLTimestamp; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping.XMLClass.XMLVersion; -import org.hibernate.metamodel.source.hbm.xml.mapping.XMLPropertyElement; import org.hibernate.metamodel.source.util.MappingHelper; /** @@ -46,120 +38,23 @@ import org.hibernate.metamodel.source.util.MappingHelper; public abstract class AbstractHbmAttributeDomainState implements AbstractAttributeBinding.DomainState { private final MappingDefaults defaults; private final Attribute attribute; - private final HibernateTypeDescriptor hibernateTypeDescriptor; - private final String accessorName; - private final String cascade; - private final boolean isOptimisticLockable; private final String nodeName; + private final String accessorName; + private final boolean isOptimisticLockable; private final Map metaAttributes; public AbstractHbmAttributeDomainState(MappingDefaults defaults, Attribute attribute, - Map entityMetaAttributes, - XMLId id) { + String nodeName, + Map metaAttributes, + String accessorName, + boolean isOptimisticLockable) { this.defaults = defaults; this.attribute = attribute; - this.hibernateTypeDescriptor = new HibernateTypeDescriptor(); - this.hibernateTypeDescriptor.setTypeName( id.getTypeAttribute() ); - this.accessorName = HbmHelper.getPropertyAccessorName( - id.getAccess(), isEmbedded(), defaults.getDefaultAccess() - ); - this.nodeName = MappingHelper.getStringValue( id.getNode(), attribute.getName() ); - this.metaAttributes = HbmHelper.extractMetas( id.getMeta(), entityMetaAttributes ); - this.cascade = defaults.getDefaultCascade(); - this.isOptimisticLockable = true; - } - - public AbstractHbmAttributeDomainState(MappingDefaults defaults, - Attribute attribute, - XMLDiscriminator discriminator) { - - this.defaults = defaults; - this.attribute = attribute; - this.hibernateTypeDescriptor = new HibernateTypeDescriptor(); - this.hibernateTypeDescriptor.setTypeName( discriminator.getType() == null ? "string" : discriminator.getType() ); - // the following does not apply to discriminators - this.accessorName = null; - this.nodeName = null; - this.metaAttributes = null; - this.cascade = null; - this.isOptimisticLockable = true; - } - - public AbstractHbmAttributeDomainState(MappingDefaults defaults, - Attribute attribute, - Map entityMetaAttributes, - XMLVersion version) { - this.defaults = defaults; - this.attribute = attribute; - this.hibernateTypeDescriptor = new HibernateTypeDescriptor(); - this.hibernateTypeDescriptor.setTypeName( version.getType() == null ? "integer" : version.getType() ); - - // the following does not apply to discriminators - this.accessorName = HbmHelper.getPropertyAccessorName( - version.getAccess(), isEmbedded(), defaults.getDefaultAccess() - ); - this.nodeName = version.getNode(); - this.metaAttributes = HbmHelper.extractMetas( version.getMeta(), entityMetaAttributes ); - this.cascade = null; - this.isOptimisticLockable = true; - } - - public AbstractHbmAttributeDomainState(MappingDefaults defaults, - Attribute attribute, - Map entityMetaAttributes, - XMLTimestamp timestamp) { - this.defaults = defaults; - this.attribute = attribute; - this.hibernateTypeDescriptor = new HibernateTypeDescriptor(); - - // Timestamp.getType() is not defined - this.hibernateTypeDescriptor.setTypeName( "db".equals( timestamp.getSource() ) ? "dbtimestamp" : "timestamp" ); - - // the following does not apply to discriminators - this.accessorName = HbmHelper.getPropertyAccessorName( - timestamp.getAccess(), isEmbedded(), defaults.getDefaultAccess() - ); - this.nodeName = timestamp.getNode(); - this.metaAttributes = HbmHelper.extractMetas( timestamp.getMeta(), entityMetaAttributes ); - this.cascade = null; - this.isOptimisticLockable = true; - } - - - public AbstractHbmAttributeDomainState(MappingDefaults defaults, - Attribute attribute, - Map entityMetaAttributes, - XMLPropertyElement property) { - this.defaults = defaults; - this.attribute = attribute; - this.hibernateTypeDescriptor = new HibernateTypeDescriptor(); - this.hibernateTypeDescriptor.setTypeName( property.getTypeAttribute() ); - this.accessorName = HbmHelper.getPropertyAccessorName( - property.getAccess(), isEmbedded(), defaults.getDefaultAccess() - ); - this.nodeName = MappingHelper.getStringValue( property.getNode(), attribute.getName() ); - this.metaAttributes = HbmHelper.extractMetas( property.getMeta(), entityMetaAttributes ); - this.cascade = defaults.getDefaultCascade(); - this.isOptimisticLockable = property.isOptimisticLock(); - } - - public AbstractHbmAttributeDomainState(MappingDefaults defaults, - Attribute attribute, - Map entityMetaAttributes, - XMLBagElement collection) { - this.defaults = defaults; - this.attribute = attribute; - this.hibernateTypeDescriptor = new HibernateTypeDescriptor(); - // TODO: is collection.getCollectionType() correct here? - this.hibernateTypeDescriptor.setTypeName( collection.getCollectionType() ); - this.accessorName = HbmHelper.getPropertyAccessorName( - collection.getAccess(), isEmbedded(), defaults.getDefaultAccess() - ); - this.nodeName = MappingHelper.getStringValue( collection.getNode(), attribute.getName() ); - this.metaAttributes = HbmHelper.extractMetas( collection.getMeta(), entityMetaAttributes ); - this.cascade = defaults.getDefaultCascade(); - this.isOptimisticLockable = collection.isOptimisticLock(); + this.nodeName = MappingHelper.getStringValue( nodeName, attribute.getName() ); + this.metaAttributes = metaAttributes; + this.accessorName = accessorName; + this.isOptimisticLockable = isOptimisticLockable; } protected final MappingDefaults getDefaults() { @@ -168,22 +63,14 @@ public abstract class AbstractHbmAttributeDomainState implements AbstractAttribu public final Attribute getAttribute() { return attribute; } - public final HibernateTypeDescriptor getHibernateTypeDescriptor() { - return hibernateTypeDescriptor; - } public final String getPropertyAccessorName() { return accessorName; } - protected abstract boolean isEmbedded(); - public final boolean isAlternateUniqueKey() { //TODO: implement return false; } - public final String getCascade() { - return cascade; - } public final boolean isOptimisticLockable() { return isOptimisticLockable; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/domain/HbmManyToOneAttributeDomainState.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/domain/HbmManyToOneAttributeDomainState.java new file mode 100644 index 0000000000..5b8e635f5a --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/domain/HbmManyToOneAttributeDomainState.java @@ -0,0 +1,168 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.source.hbm.state.domain; + +import java.util.Map; + +import org.dom4j.Attribute; +import org.dom4j.Element; + +import org.hibernate.FetchMode; +import org.hibernate.MappingException; +import org.hibernate.cfg.HbmBinder; +import org.hibernate.cfg.Mappings; +import org.hibernate.mapping.Fetchable; +import org.hibernate.mapping.OneToOne; +import org.hibernate.mapping.PropertyGeneration; +import org.hibernate.metamodel.binding.EntityBinding; +import org.hibernate.metamodel.binding.HibernateTypeDescriptor; +import org.hibernate.metamodel.binding.ManyToOneAttributeBinding; +import org.hibernate.metamodel.binding.MappingDefaults; +import org.hibernate.metamodel.binding.SimpleAttributeBinding; +import org.hibernate.metamodel.domain.MetaAttribute; +import org.hibernate.metamodel.source.Metadata; +import org.hibernate.metamodel.source.hbm.HbmHelper; +import org.hibernate.metamodel.source.hbm.xml.mapping.XMLManyToOneElement; +import org.hibernate.metamodel.source.util.DomHelper; +import org.hibernate.metamodel.source.util.MappingHelper; +import org.hibernate.tuple.component.Dom4jComponentTuplizer; + +/** + * @author Gail Badner + */ +public class HbmManyToOneAttributeDomainState + extends AbstractHbmAttributeDomainState + implements ManyToOneAttributeBinding.DomainState { + + private final HibernateTypeDescriptor hibernateTypeDescriptor = new HibernateTypeDescriptor(); + private final XMLManyToOneElement manyToOne; + private final String cascade; + + public HbmManyToOneAttributeDomainState(MappingDefaults defaults, + org.hibernate.metamodel.domain.Attribute attribute, + Map entityMetaAttributes, + XMLManyToOneElement manyToOne) { + super( + defaults, + attribute, + manyToOne.getNode(), + HbmHelper.extractMetas( manyToOne.getMeta(), entityMetaAttributes ), + HbmHelper.getPropertyAccessorName( manyToOne.getAccess(), manyToOne.isEmbedXml(), defaults.getDefaultAccess() ), + manyToOne.isOptimisticLock() + ); + + this.hibernateTypeDescriptor.setTypeName( getReferencedEntityName() ); + this.manyToOne = manyToOne; + this.cascade = MappingHelper.getStringValue( manyToOne.getCascade(), defaults.getDefaultCascade() ); + } + + // TODO: is this needed??? + protected boolean isEmbedded() { + return MappingHelper.getBooleanValue( manyToOne.isEmbedXml(), true ); + } + + public HibernateTypeDescriptor getHibernateTypeDescriptor() { + return hibernateTypeDescriptor; + } + + // same as for plural attributes... + public FetchMode getFetchMode() { + FetchMode fetchMode; + if ( manyToOne.getFetch() != null ) { + fetchMode = "join".equals( manyToOne.getFetch() ) ? FetchMode.JOIN : FetchMode.SELECT; + } + else { + String jfNodeValue = ( manyToOne.getOuterJoin().value() == null ? "auto" : manyToOne.getOuterJoin().value() ); + if ( "auto".equals( jfNodeValue ) ) { + fetchMode = FetchMode.DEFAULT; + } + else if ( "true".equals( jfNodeValue ) ) { + fetchMode = FetchMode.JOIN; + } + else { + fetchMode = FetchMode.SELECT; + } + } + return fetchMode; + } + + public boolean isLazy() { + return manyToOne.getLazy() == null || + isUnwrapProxy() || + manyToOne.getLazy().equals( "proxy" ); + //TODO: better to degrade to lazy="false" if uninstrumented + } + + public boolean isUnwrapProxy() { + return "no-proxy".equals( manyToOne.getLazy() ); + } + + public String getReferencedAttributeName() { + return manyToOne.getPropertyRef(); + } + + public String getReferencedEntityName() { + String entityName = manyToOne.getEntityName(); + return entityName == null ? + HbmHelper.getClassName( manyToOne.getClazz(), getDefaults().getPackageName() ) : + entityName.intern(); + } + + public String getCascade() { + return MappingHelper.getStringValue( manyToOne.getCascade(), getDefaults().getDefaultCascade() ); + } + + public boolean ignoreNotFound() { + return "ignore".equals( manyToOne.getNotFound() ); + } + + /* + void junk() { + if( getReferencedPropertyName() != null && ! ignoreNotFound() ) { + mappings.addSecondPass( new ManyToOneSecondPass(manyToOne) ); + } + } + */ + + public boolean isInsertable() { + return MappingHelper.getBooleanValue( manyToOne.isInsert(), true ); + } + + public boolean isUpdateable() { + return MappingHelper.getBooleanValue( manyToOne.isUnique(), true ); + } + + public String getForeignkeyName() { + return manyToOne.getForeignKey(); + } + + public boolean isKeyCasadeDeleteEnabled() { + //TODO: implement + return false; + } + public String getUnsavedValue() { + //TODO: implement + return null; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/domain/HbmPluralAttributeDomainState.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/domain/HbmPluralAttributeDomainState.java index 57d1c6a82b..4728b5c531 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/domain/HbmPluralAttributeDomainState.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/domain/HbmPluralAttributeDomainState.java @@ -33,6 +33,7 @@ import org.hibernate.MappingException; import org.hibernate.metamodel.binding.CollectionElement; import org.hibernate.metamodel.binding.CustomSQL; import org.hibernate.metamodel.binding.ElementCollectionElement; +import org.hibernate.metamodel.binding.HibernateTypeDescriptor; import org.hibernate.metamodel.binding.MappingDefaults; import org.hibernate.metamodel.binding.PluralAttributeBinding; import org.hibernate.metamodel.domain.Attribute; @@ -53,13 +54,42 @@ import org.hibernate.metamodel.source.util.MappingHelper; */ public class HbmPluralAttributeDomainState extends AbstractHbmAttributeDomainState implements PluralAttributeBinding.DomainState { private final XMLBagElement collection; + private final HibernateTypeDescriptor hibernateTypeDescriptor = new HibernateTypeDescriptor(); + private final String cascade; public HbmPluralAttributeDomainState(MappingDefaults defaults, XMLBagElement collection, Map entityMetaAttributes, Attribute attribute) { - super( defaults, attribute, entityMetaAttributes, collection ); + super( + defaults, + attribute, + collection.getNode(), + HbmHelper.extractMetas( collection.getMeta(), entityMetaAttributes ), + HbmHelper.getPropertyAccessorName( collection.getAccess(), collection.isEmbedXml(), defaults.getDefaultAccess() ), + collection.isOptimisticLock() + ); this.collection = collection; + // TODO: is collection.getCollectionType() correct here? + this.hibernateTypeDescriptor.setTypeName( collection.getCollectionType() ); + this.cascade = MappingHelper.getStringValue( collection.getCascade(), defaults.getDefaultCascade() ); + //Attribute typeNode = collectionElement.attribute( "collection-type" ); + //if ( typeNode != null ) { + // TODO: implement when typedef binding is implemented + /* + String typeName = typeNode.getValue(); + TypeDef typeDef = mappings.getTypeDef( typeName ); + if ( typeDef != null ) { + collectionBinding.setTypeName( typeDef.getTypeClass() ); + collectionBinding.setTypeParameters( typeDef.getParameters() ); + } + else { + collectionBinding.setTypeName( typeName ); + } + */ + //} + //TODO: fix this!!! + this.hibernateTypeDescriptor.setTypeName( collection.getCollectionType() ); } public FetchMode getFetchMode() { @@ -174,24 +204,9 @@ public class HbmPluralAttributeDomainState extends AbstractHbmAttributeDomainSta + collection.getPersister() ); } } - public String getTypeName() { - // TODO: does this go here??? - //Attribute typeNode = collectionElement.attribute( "collection-type" ); - //if ( typeNode != null ) { - // TODO: implement when typedef binding is implemented - /* - String typeName = typeNode.getValue(); - TypeDef typeDef = mappings.getTypeDef( typeName ); - if ( typeDef != null ) { - collectionBinding.setTypeName( typeDef.getTypeClass() ); - collectionBinding.setTypeParameters( typeDef.getParameters() ); - } - else { - collectionBinding.setTypeName( typeName ); - } - */ - //} - return null; + + public HibernateTypeDescriptor getHibernateTypeDescriptor() { + return hibernateTypeDescriptor; } public java.util.Map getFilters() { @@ -257,6 +272,10 @@ public class HbmPluralAttributeDomainState extends AbstractHbmAttributeDomainSta collection.getLoader().getQueryRef(); } + public String getCascade() { + return cascade; + } + public boolean isKeyCasadeDeleteEnabled() { //TODO: implement return false; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/domain/HbmSimpleAttributeDomainState.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/domain/HbmSimpleAttributeDomainState.java index 55a80c8546..0a3e4f906c 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/domain/HbmSimpleAttributeDomainState.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/domain/HbmSimpleAttributeDomainState.java @@ -27,9 +27,11 @@ import java.util.Map; import org.hibernate.MappingException; import org.hibernate.mapping.PropertyGeneration; +import org.hibernate.metamodel.binding.HibernateTypeDescriptor; import org.hibernate.metamodel.binding.MappingDefaults; import org.hibernate.metamodel.binding.SimpleAttributeBinding; import org.hibernate.metamodel.domain.MetaAttribute; +import org.hibernate.metamodel.source.hbm.HbmHelper; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping.XMLClass.XMLDiscriminator; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping.XMLClass.XMLId; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping.XMLClass.XMLTimestamp; @@ -41,6 +43,7 @@ import org.hibernate.metamodel.source.util.MappingHelper; * @author Gail Badner */ public class HbmSimpleAttributeDomainState extends AbstractHbmAttributeDomainState implements SimpleAttributeBinding.DomainState { + private final HibernateTypeDescriptor hibernateTypeDescriptor = new HibernateTypeDescriptor(); private final boolean isLazy; private final PropertyGeneration propertyGeneration; private final boolean isInsertable; @@ -50,8 +53,19 @@ public class HbmSimpleAttributeDomainState extends AbstractHbmAttributeDomainSta org.hibernate.metamodel.domain.Attribute attribute, Map entityMetaAttributes, XMLId id) { - super( defaults, attribute, entityMetaAttributes, id ); + super( + defaults, + attribute, + id.getNode(), + HbmHelper.extractMetas( id.getMeta(), entityMetaAttributes ), + HbmHelper.getPropertyAccessorName( id.getAccess(), false, defaults.getDefaultAccess() ) , + true + ); + this.isLazy = false; + if ( id.getType() != null ) { + this.hibernateTypeDescriptor.setTypeName( id.getType().getName() ); + } // TODO: how should these be set??? this.propertyGeneration = PropertyGeneration.parse( null ); @@ -64,7 +78,10 @@ public class HbmSimpleAttributeDomainState extends AbstractHbmAttributeDomainSta org.hibernate.metamodel.domain.Attribute attribute, Map entityMetaAttributes, XMLDiscriminator discriminator) { - super( defaults, attribute, discriminator ); + super( + defaults, attribute, null, null, null, true + ); + this.hibernateTypeDescriptor.setTypeName( discriminator.getType() == null ? "string" : discriminator.getType() ); this.isLazy = false; this.propertyGeneration = PropertyGeneration.NEVER; @@ -77,7 +94,15 @@ public class HbmSimpleAttributeDomainState extends AbstractHbmAttributeDomainSta Map entityMetaAttributes, XMLVersion version) { - super( defaults, attribute, entityMetaAttributes, version ); + super( + defaults, + attribute, + version.getNode(), + HbmHelper.extractMetas( version.getMeta(), entityMetaAttributes ), + HbmHelper.getPropertyAccessorName( version.getAccess(), false, defaults.getDefaultAccess() ) , + true + ); + this.hibernateTypeDescriptor.setTypeName( version.getType() == null ? "integer" : version.getType() ); this.isLazy = false; // for version properties marked as being generated, make sure they are "always" @@ -96,7 +121,16 @@ public class HbmSimpleAttributeDomainState extends AbstractHbmAttributeDomainSta Map entityMetaAttributes, XMLTimestamp timestamp) { - super( defaults, attribute, entityMetaAttributes, timestamp ); + super( + defaults, + attribute, + timestamp.getNode(), + HbmHelper.extractMetas( timestamp.getMeta(), entityMetaAttributes ), + HbmHelper.getPropertyAccessorName( timestamp.getAccess(), false, defaults.getDefaultAccess() ), + true + ); + // Timestamp.getType() is not defined + this.hibernateTypeDescriptor.setTypeName( "db".equals( timestamp.getSource() ) ? "dbtimestamp" : "timestamp" ); this.isLazy = false; // for version properties marked as being generated, make sure they are "always" @@ -114,7 +148,14 @@ public class HbmSimpleAttributeDomainState extends AbstractHbmAttributeDomainSta org.hibernate.metamodel.domain.Attribute attribute, Map entityMetaAttributes, XMLPropertyElement property) { - super( defaults, attribute, entityMetaAttributes, property ); + super( + defaults, + attribute, + property.getNode(), + HbmHelper.extractMetas( property.getMeta(), entityMetaAttributes ), + HbmHelper.getPropertyAccessorName( property.getAccess(), false, defaults.getDefaultAccess() ), + property.isOptimisticLock() + ); this.isLazy = property.isLazy(); this.propertyGeneration = PropertyGeneration.parse( property.getGenerated() ); @@ -150,11 +191,14 @@ public class HbmSimpleAttributeDomainState extends AbstractHbmAttributeDomainSta } } - @Override protected boolean isEmbedded() { return false; } + public HibernateTypeDescriptor getHibernateTypeDescriptor() { + return hibernateTypeDescriptor; + } + public boolean isLazy() { return isLazy; } @@ -168,6 +212,11 @@ public class HbmSimpleAttributeDomainState extends AbstractHbmAttributeDomainSta public boolean isUpdateable() { return isUpdateable; } + + public String getCascade() { + return null; + } + public boolean isKeyCasadeDeleteEnabled() { //TODO: implement return false; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/relational/HbmColumnRelationalState.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/relational/HbmColumnRelationalState.java index d00126e4af..ccac43e7e1 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/relational/HbmColumnRelationalState.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/relational/HbmColumnRelationalState.java @@ -27,13 +27,14 @@ import java.util.Set; import org.hibernate.MappingException; import org.hibernate.cfg.NamingStrategy; -import org.hibernate.metamodel.binding.SimpleAttributeBinding; +import org.hibernate.metamodel.binding.AbstractAttributeBinding; import org.hibernate.metamodel.relational.Size; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLColumnElement; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping.XMLClass.XMLDiscriminator; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping.XMLClass.XMLId; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping.XMLClass.XMLTimestamp; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping.XMLClass.XMLVersion; +import org.hibernate.metamodel.source.hbm.xml.mapping.XMLManyToOneElement; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLPropertyElement; import org.hibernate.metamodel.source.util.MappingHelper; @@ -42,7 +43,7 @@ import org.hibernate.metamodel.source.util.MappingHelper; /** * @author Gail Badner */ -public class HbmColumnRelationalState implements SimpleAttributeBinding.ColumnRelationalState { +public class HbmColumnRelationalState implements AbstractAttributeBinding.ColumnRelationalState { private final HbmSimpleValueRelationalStateContainer container; private final String explicitColumnName; private final Size size; @@ -99,6 +100,25 @@ public class HbmColumnRelationalState implements SimpleAttributeBinding.ColumnRe this.indexes.addAll( container.getPropertyIndexes() ); } + HbmColumnRelationalState(XMLManyToOneElement manyToOne, + HbmSimpleValueRelationalStateContainer container) { + this.container = container; + this.explicitColumnName = manyToOne.getName(); + this.size = new Size(); + this.isNullable =! MappingHelper.getBooleanValue( manyToOne.isNotNull(), false ); + this.isUnique = manyToOne.isUnique(); + this.checkCondition = null; + this.defaultColumnValue = null; + this.sqlType = null; + this.customWrite = null; + this.customRead = null; + this.comment = null; + this.uniqueKeys = MappingHelper.getStringValueTokens( manyToOne.getUniqueKey(), ", " ); + this.uniqueKeys.addAll( container.getPropertyUniqueKeys() ); + this.indexes = MappingHelper.getStringValueTokens( manyToOne.getIndex(), ", " ); + this.indexes.addAll( container.getPropertyIndexes() ); + } + HbmColumnRelationalState(XMLId id, HbmSimpleValueRelationalStateContainer container) { if ( id.getColumn() != null && ! id.getColumn().isEmpty() ) { @@ -152,7 +172,7 @@ public class HbmColumnRelationalState implements SimpleAttributeBinding.ColumnRe this.isUnique = false; this.checkCondition = null; this.defaultColumnValue = null; - this.sqlType = null; // TODO: figure out the correct setting + this.sqlType = null; this.customWrite = null; this.customRead = null; this.comment = null; @@ -170,7 +190,7 @@ public class HbmColumnRelationalState implements SimpleAttributeBinding.ColumnRe this.isUnique = true; // well, it should hopefully be unique... this.checkCondition = null; this.defaultColumnValue = null; - this.sqlType = null; // TODO: figure out the correct setting + this.sqlType = null; this.customWrite = null; this.customRead = null; this.comment = null; @@ -187,7 +207,7 @@ public class HbmColumnRelationalState implements SimpleAttributeBinding.ColumnRe public Size getSize() { return size; } - private static Size createSize(String length, String scale, String precision) { + protected static Size createSize(String length, String scale, String precision) { // TODO: should this set defaults if length, scale, precision is not specified? Size size = new Size(); if ( length != null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/relational/HbmDerivedValueRelationalState.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/relational/HbmDerivedValueRelationalState.java index ed2e966660..59e2e652c9 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/relational/HbmDerivedValueRelationalState.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/relational/HbmDerivedValueRelationalState.java @@ -23,8 +23,6 @@ */ package org.hibernate.metamodel.source.hbm.state.relational; -import org.dom4j.Element; - import org.hibernate.metamodel.binding.SimpleAttributeBinding; /** diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/relational/HbmManyToOneRelationalStateContainer.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/relational/HbmManyToOneRelationalStateContainer.java new file mode 100644 index 0000000000..2048396302 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/relational/HbmManyToOneRelationalStateContainer.java @@ -0,0 +1,54 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.source.hbm.state.relational; + +import org.hibernate.metamodel.binding.ManyToOneAttributeBinding; +import org.hibernate.metamodel.binding.MappingDefaults; +import org.hibernate.metamodel.source.hbm.xml.mapping.XMLManyToOneElement; + +/** + * @author Gail Badner + */ +public class HbmManyToOneRelationalStateContainer extends HbmSimpleValueRelationalStateContainer +implements ManyToOneAttributeBinding.RelationalState { + + private final boolean isLogicalOneToOne; + private final String foreignKeyName; + + public HbmManyToOneRelationalStateContainer(MappingDefaults defaults, + boolean autoColumnCreation, + XMLManyToOneElement manyToOne ) { + super( defaults, autoColumnCreation, manyToOne ); + this.isLogicalOneToOne = manyToOne.isUnique(); + this.foreignKeyName = manyToOne.getForeignKey(); + } + + public boolean isLogicalOneToOne() { + return isLogicalOneToOne; + } + + public String getForeignKeyName() { + return foreignKeyName; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/relational/HbmSimpleValueRelationalStateContainer.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/relational/HbmSimpleValueRelationalStateContainer.java index eeff419417..975a7553bd 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/relational/HbmSimpleValueRelationalStateContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/state/relational/HbmSimpleValueRelationalStateContainer.java @@ -30,13 +30,16 @@ import java.util.Set; import org.hibernate.MappingException; import org.hibernate.cfg.NamingStrategy; +import org.hibernate.metamodel.binding.HibernateTypeDescriptor; import org.hibernate.metamodel.binding.MappingDefaults; import org.hibernate.metamodel.binding.SimpleAttributeBinding; +import org.hibernate.metamodel.relational.Size; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLColumnElement; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping.XMLClass.XMLDiscriminator; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping.XMLClass.XMLId; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping.XMLClass.XMLTimestamp; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping.XMLClass.XMLVersion; +import org.hibernate.metamodel.source.hbm.xml.mapping.XMLManyToOneElement; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLPropertyElement; /** @@ -47,6 +50,7 @@ public class HbmSimpleValueRelationalStateContainer implements SimpleAttributeBi private final Set propertyUniqueKeys; private final Set propertyIndexes; private final Set singleValueStates; + private final HibernateTypeDescriptor hibernateTypeDescriptor = new HibernateTypeDescriptor(); public NamingStrategy getNamingStrategy() { return defaults.getNamingStrategy(); @@ -67,6 +71,7 @@ public class HbmSimpleValueRelationalStateContainer implements SimpleAttributeBi else if ( id.getColumn() != null ) { throw new MappingException( "column attribute may not be used together with subelement" ); } + this.hibernateTypeDescriptor.setTypeName( id.getTypeAttribute() ); } public HbmSimpleValueRelationalStateContainer(MappingDefaults defaults, @@ -82,6 +87,7 @@ public class HbmSimpleValueRelationalStateContainer implements SimpleAttributeBi else if ( discriminator.getColumn() != null || discriminator.getFormula() != null) { throw new MappingException( "column/formula attribute may not be used together with / subelement" ); } + this.hibernateTypeDescriptor.setTypeName( discriminator.getType() == null ? "string" : discriminator.getType() ); } public HbmSimpleValueRelationalStateContainer(MappingDefaults defaults, @@ -97,6 +103,7 @@ public class HbmSimpleValueRelationalStateContainer implements SimpleAttributeBi else if ( version.getColumn() != null ) { throw new MappingException( "column attribute may not be used together with subelement" ); } + this.hibernateTypeDescriptor.setTypeName( version.getType() == null ? "integer" : version.getType() ); } public HbmSimpleValueRelationalStateContainer(MappingDefaults defaults, @@ -112,6 +119,7 @@ public class HbmSimpleValueRelationalStateContainer implements SimpleAttributeBi else if ( timestamp.getColumn() != null ) { throw new MappingException( "column attribute may not be used together with subelement" ); } + this.hibernateTypeDescriptor.setTypeName( "db".equals( timestamp.getSource() ) ? "dbtimestamp" : "timestamp" ); } public HbmSimpleValueRelationalStateContainer(MappingDefaults defaults, @@ -127,6 +135,22 @@ public class HbmSimpleValueRelationalStateContainer implements SimpleAttributeBi else if ( property.getColumn() != null || property.getFormula() != null) { throw new MappingException( "column/formula attribute may not be used together with / subelement" ); } + this.hibernateTypeDescriptor.setTypeName( property.getTypeAttribute() ); + } + + public HbmSimpleValueRelationalStateContainer(MappingDefaults defaults, + boolean autoColumnCreation, + XMLManyToOneElement manyToOne) { + this( defaults, manyToOne.getColumnOrFormula() ); + if ( singleValueStates.isEmpty() ) { + if ( manyToOne.getColumn() == null && manyToOne.getFormula() == null && ! autoColumnCreation ) { + throw new MappingException( "No column or formula to map and auto column creation is disabled." ); + } + singleValueStates.add( new HbmColumnRelationalState( manyToOne, this ) ); + } + else if ( manyToOne.getColumn() != null || manyToOne.getFormula() != null) { + throw new MappingException( "column/formula attribute may not be used together with / subelement" ); + } } private HbmSimpleValueRelationalStateContainer(MappingDefaults defaults, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/EntityReferenceResolver.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/EntityReferenceResolver.java new file mode 100644 index 0000000000..0a9cd30803 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/EntityReferenceResolver.java @@ -0,0 +1,75 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.source.internal; + +import org.hibernate.MappingException; +import org.hibernate.metamodel.binding.AttributeBinding; +import org.hibernate.metamodel.binding.EntityBinding; +import org.hibernate.metamodel.binding.EntityReferencingAttributeBinding; +import org.hibernate.metamodel.source.spi.MetadataImplementor; + +/** + * @author Gail Badner + */ +class EntityReferenceResolver { + + private final MetadataImplementor metadata; + + EntityReferenceResolver(MetadataImplementor metadata) { + this.metadata = metadata; + } + + void resolve() { + for ( EntityBinding entityBinding : metadata.getEntityBindings() ) { + for ( EntityReferencingAttributeBinding attributeBinding : entityBinding.getEntityReferencingAttributeBindings() ) { + resolve( attributeBinding ); + } + } + } + + private void resolve(EntityReferencingAttributeBinding attributeBinding) { + if ( attributeBinding.getReferencedEntityName() == null ) { + throw new IllegalArgumentException( "attributeBinding has null entityName: " + attributeBinding.getAttribute().getName() ); + } + EntityBinding entityBinding = metadata.getEntityBinding( attributeBinding.getReferencedEntityName() ); + if ( entityBinding == null ) { + throw new org.hibernate.MappingException( + "Attribute [" + attributeBinding.getAttribute().getName() + + "] refers to unknown entity: [" + attributeBinding.getReferencedEntityName() + "]" ); + } + AttributeBinding referencedAttributeBinding = + attributeBinding.getReferencedAttributeName() == null ? + entityBinding.getEntityIdentifier().getValueBinding() : + entityBinding.getAttributeBinding( attributeBinding.getReferencedAttributeName() ); + if ( referencedAttributeBinding == null ) { + // TODO: does attribute name include path w/ entity name? + throw new MappingException( + "Attribute [" + attributeBinding.getAttribute().getName() + + "] refers to unknown attribute: [" + attributeBinding.getReferencedEntityName() + "]" + ); + } + attributeBinding.resolveReference( referencedAttributeBinding ); + referencedAttributeBinding.addEntityReferencingAttributeBinding( attributeBinding ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java index 8ebaa1b260..aa717ba6a4 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java @@ -41,6 +41,7 @@ import org.hibernate.cfg.NamingStrategy; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.mapping.MetadataSource; import org.hibernate.metamodel.binding.EntityBinding; +import org.hibernate.metamodel.binding.EntityReferencingAttributeBinding; import org.hibernate.metamodel.binding.FetchProfile; import org.hibernate.metamodel.binding.PluralAttributeBinding; import org.hibernate.metamodel.relational.Database; @@ -88,6 +89,8 @@ public class MetadataImpl implements Metadata, MetadataImplementor, Serializable applyAnnotationMappings( metadataSources, processedEntityNames ); applyHibernateMappings( metadataSources, processedEntityNames ); } + + new EntityReferenceResolver( this ).resolve(); } private void applyHibernateMappings(MetadataSources metadataSources, List processedEntityNames) {