HHH-6504: Added basic metamodel support for maps (and corrected a few implementation issues with list support). Still need to address remaining types of map key specifications (other than <map-key>).

This commit is contained in:
John Verhaeg 2012-04-12 10:57:43 -05:00
parent 5b2cfd3c7c
commit 6dceff93a6
16 changed files with 636 additions and 194 deletions

View File

@ -45,7 +45,8 @@ import org.hibernate.id.factory.IdentifierGeneratorFactory;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.internal.HibernateTypeHelper.ReflectedCollectionJavaTypes;
import org.hibernate.metamodel.internal.source.hbm.ListAttributeSourceImpl;
import org.hibernate.metamodel.internal.source.hbm.ListAttributeSource;
import org.hibernate.metamodel.internal.source.hbm.MapAttributeSource;
import org.hibernate.metamodel.spi.binding.AbstractPluralAttributeBinding;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.AttributeBindingContainer;
@ -63,6 +64,7 @@ import org.hibernate.metamodel.spi.binding.IndexedPluralAttributeBinding;
import org.hibernate.metamodel.spi.binding.InheritanceType;
import org.hibernate.metamodel.spi.binding.ListBinding;
import org.hibernate.metamodel.spi.binding.ManyToOneAttributeBinding;
import org.hibernate.metamodel.spi.binding.MapBinding;
import org.hibernate.metamodel.spi.binding.MetaAttribute;
import org.hibernate.metamodel.spi.binding.PluralAttributeBinding;
import org.hibernate.metamodel.spi.binding.PluralAttributeElementNature;
@ -105,6 +107,7 @@ import org.hibernate.metamodel.spi.source.ExplicitHibernateTypeSource;
import org.hibernate.metamodel.spi.source.IdentifierSource;
import org.hibernate.metamodel.spi.source.IdentifierSource.Nature;
import org.hibernate.metamodel.spi.source.InLineViewSource;
import org.hibernate.metamodel.spi.source.IndexedPluralAttributeSource;
import org.hibernate.metamodel.spi.source.LocalBindingContext;
import org.hibernate.metamodel.spi.source.MappingDefaults;
import org.hibernate.metamodel.spi.source.MappingException;
@ -167,6 +170,55 @@ public class Binder {
return new org.hibernate.internal.util.Value< Class< ? >>( deferredInitializer );
}
private static String getIdentifierUnsavedValue(IdentifierSource identifierSource, IdGenerator generator) {
if ( identifierSource == null ) {
throw new IllegalArgumentException( "identifierSource must be non-null." );
}
if ( generator == null || StringHelper.isEmpty( generator.getStrategy() ) ) {
throw new IllegalArgumentException( "generator must be non-null and its strategy must be non-empty." );
}
String unsavedValue = null;
if ( identifierSource.getUnsavedValue() != null ) {
unsavedValue = identifierSource.getUnsavedValue();
}
else if ( "assigned".equals( generator.getStrategy() ) ) {
unsavedValue = "undefined";
}
else {
switch ( identifierSource.getNature() ) {
case SIMPLE: {
// unsavedValue = null;
break;
}
case COMPOSITE: {
// The generator strategy should be "assigned" and processed above.
throw new IllegalStateException(
String.format(
"Expected generator strategy for composite ID: 'assigned'; instead it is: %s",
generator.getStrategy()
)
);
}
case AGGREGATED_COMPOSITE: {
// TODO: if the component only contains 1 attribute (when flattened)
// and it is not an association then null should be returned;
// otherwise "undefined" should be returned.
throw new NotYetImplementedException(
String.format(
"Unsaved value for (%s) identifier not implemented yet.",
identifierSource.getNature()
)
);
}
default: {
throw new AssertionFailure(
String.format( "Unexpected identifier nature: %s", identifierSource.getNature() )
);
}
}
}
return unsavedValue;
}
private final MetadataImplementor metadata;
private final IdentifierGeneratorFactory identifierGeneratorFactory;
private final ObjectNameNormalizer nameNormalizer;
@ -176,6 +228,7 @@ public class Binder {
private final HashMap< String, AttributeSource > attributeSourcesByName = new HashMap< String, AttributeSource >();
private final LinkedList< LocalBindingContext > bindingContexts = new LinkedList< LocalBindingContext >();
private final LinkedList< InheritanceType > inheritanceTypes = new LinkedList< InheritanceType >();
private final LinkedList< EntityMode > entityModes = new LinkedList< EntityMode >();
private final HibernateTypeHelper typeHelper; // todo: refactor helper and remove redundant methods in this class
@ -210,6 +263,31 @@ public class Binder {
return entityName + "." + attributeName;
}
private void bindAggregatedCompositeIdentifier(
EntityBinding rootEntityBinding,
AggregatedCompositeIdentifierSource identifierSource) {
// locate the attribute binding
final CompositeAttributeBinding idAttributeBinding =
( CompositeAttributeBinding ) bindAttribute( rootEntityBinding, identifierSource.getIdentifierAttributeSource() );
// Configure ID generator
IdGenerator generator = identifierSource.getIdentifierGeneratorDescriptor();
if ( generator == null ) {
final Map< String, String > params = new HashMap< String, String >();
params.put( IdentifierGenerator.ENTITY_NAME, rootEntityBinding.getEntity().getName() );
generator = new IdGenerator( "default_assign_identity_generator", "assigned", params );
}
// determine the unsaved value mapping
final String unsavedValue = getIdentifierUnsavedValue( identifierSource, generator );
rootEntityBinding.getHierarchyDetails().getEntityIdentifier().bindAsSingleAttributeIdentifier(
idAttributeBinding,
generator,
unsavedValue
);
}
private AttributeBinding bindAttribute(
final AttributeBindingContainer attributeBindingContainer,
final AttributeSource attributeSource ) {
@ -491,7 +569,7 @@ public class Binder {
if ( attributeBinding.getPluralAttributeElementBinding().getPluralAttributeElementNature() == PluralAttributeElementNature.BASIC ) {
if ( pluralAttributeNature == PluralAttributeNature.SET ) {
bindBasicElementTablePrimaryKey( attributeBinding );
} else if ( pluralAttributeNature == PluralAttributeNature.LIST ) {
} else if ( pluralAttributeNature == PluralAttributeNature.LIST || pluralAttributeNature == PluralAttributeNature.MAP ) {
bindIndexedTablePrimaryKey( ( IndexedPluralAttributeBinding ) attributeBinding );
} else {
throw new NotYetImplementedException( "Only Sets with basic elements are supported so far." );
@ -771,121 +849,6 @@ public class Binder {
}
}
private void bindSimpleIdentifier( final EntityBinding rootEntityBinding, final SimpleIdentifierSource identifierSource ) {
// locate the attribute binding
final BasicAttributeBinding idAttributeBinding =
( BasicAttributeBinding ) bindAttribute( rootEntityBinding, identifierSource.getIdentifierAttributeSource() );
// Configure ID generator
IdGenerator generator = identifierSource.getIdentifierGeneratorDescriptor();
if ( generator == null ) {
final Map< String, String > params = new HashMap< String, String >();
params.put( IdentifierGenerator.ENTITY_NAME, rootEntityBinding.getEntity().getName() );
generator = new IdGenerator( "default_assign_identity_generator", "assigned", params );
}
// determine the unsaved value mapping
final String unsavedValue = getIdentifierUnsavedValue( identifierSource, generator );
rootEntityBinding.getHierarchyDetails().getEntityIdentifier().bindAsSingleAttributeIdentifier(
idAttributeBinding,
generator,
unsavedValue
);
}
private static String getIdentifierUnsavedValue(IdentifierSource identifierSource, IdGenerator generator) {
if ( identifierSource == null ) {
throw new IllegalArgumentException( "identifierSource must be non-null." );
}
if ( generator == null || StringHelper.isEmpty( generator.getStrategy() ) ) {
throw new IllegalArgumentException( "generator must be non-null and its strategy must be non-empty." );
}
String unsavedValue = null;
if ( identifierSource.getUnsavedValue() != null ) {
unsavedValue = identifierSource.getUnsavedValue();
}
else if ( "assigned".equals( generator.getStrategy() ) ) {
unsavedValue = "undefined";
}
else {
switch ( identifierSource.getNature() ) {
case SIMPLE: {
unsavedValue = null;
break;
}
case COMPOSITE: {
// The generator strategy should be "assigned" and processed above.
throw new IllegalStateException(
String.format(
"Expected generator strategy for composite ID: 'assigned'; instead it is: %s",
generator.getStrategy()
)
);
}
case AGGREGATED_COMPOSITE: {
// TODO: if the component only contains 1 attribute (when flattened)
// and it is not an association then null should be returned;
// otherwise "undefined" should be returned.
throw new NotYetImplementedException(
String.format(
"Unsaved value for (%s) identifier not implemented yet.",
identifierSource.getNature()
)
);
}
default: {
throw new AssertionFailure(
String.format( "Unexpected identifier nature: %s", identifierSource.getNature() )
);
}
}
}
return unsavedValue;
}
private void bindAggregatedCompositeIdentifier(
EntityBinding rootEntityBinding,
AggregatedCompositeIdentifierSource identifierSource) {
// locate the attribute binding
final CompositeAttributeBinding idAttributeBinding =
( CompositeAttributeBinding ) bindAttribute( rootEntityBinding, identifierSource.getIdentifierAttributeSource() );
// Configure ID generator
IdGenerator generator = identifierSource.getIdentifierGeneratorDescriptor();
if ( generator == null ) {
final Map< String, String > params = new HashMap< String, String >();
params.put( IdentifierGenerator.ENTITY_NAME, rootEntityBinding.getEntity().getName() );
generator = new IdGenerator( "default_assign_identity_generator", "assigned", params );
}
// determine the unsaved value mapping
final String unsavedValue = getIdentifierUnsavedValue( identifierSource, generator );
rootEntityBinding.getHierarchyDetails().getEntityIdentifier().bindAsSingleAttributeIdentifier(
idAttributeBinding,
generator,
unsavedValue
);
}
private void bindNonAggregatedCompositeIdentifier(
EntityBinding rootEntityBinding,
NonAggregatedCompositeIdentifierSource identifierSource) {
// 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 ) {
final PrimaryKey primaryKey = attributeBinding.getPluralAttributeKeyBinding().getCollectionTable().getPrimaryKey();
final ForeignKey foreignKey = attributeBinding.getPluralAttributeKeyBinding().getForeignKey();
@ -918,7 +881,7 @@ public class Binder {
private AbstractPluralAttributeBinding bindListAttribute(
final AttributeBindingContainer attributeBindingContainer,
final PluralAttributeSource attributeSource,
final ListAttributeSource attributeSource,
PluralAttribute attribute ) {
if ( attribute == null ) {
attribute = attributeBindingContainer.getAttributeContainer().createList( attributeSource.getName() );
@ -931,7 +894,7 @@ public class Binder {
attributeSource.isIncludedInOptimisticLocking(),
false,
createMetaAttributeContext( attributeBindingContainer, attributeSource ),
((ListAttributeSourceImpl)attributeSource).getIndexSource().base() );
attributeSource.getIndexSource().base() );
}
private ManyToOneAttributeBinding bindManyToOneAttribute(
@ -1010,6 +973,40 @@ public class Binder {
return attributeBinding;
}
private AbstractPluralAttributeBinding bindMapAttribute(
final AttributeBindingContainer attributeBindingContainer,
final MapAttributeSource attributeSource,
PluralAttribute attribute ) {
if ( attribute == null ) {
attribute = attributeBindingContainer.getAttributeContainer().createMap( attributeSource.getName() );
}
return attributeBindingContainer.makeMapAttributeBinding(
attribute,
pluralAttributeElementNature( attributeSource ),
pluralAttributeKeyBinding( attributeBindingContainer, attributeSource ),
propertyAccessorName( attributeSource ),
attributeSource.isIncludedInOptimisticLocking(),
false,
createMetaAttributeContext( attributeBindingContainer, attributeSource ) );
}
private void bindNonAggregatedCompositeIdentifier(
EntityBinding rootEntityBinding,
NonAggregatedCompositeIdentifierSource identifierSource) {
// 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 AbstractPluralAttributeBinding bindPluralAttribute(
final AttributeBindingContainer attributeBindingContainer,
final PluralAttributeSource attributeSource ) {
@ -1025,8 +1022,11 @@ public class Binder {
attributeBinding = bindSetAttribute( attributeBindingContainer, attributeSource, attribute );
resolvedType = resolveSetType( ( SetBinding ) attributeBinding );
} else if ( nature == PluralAttributeNature.LIST ) {
attributeBinding = bindListAttribute( attributeBindingContainer, attributeSource, attribute );
attributeBinding = bindListAttribute( attributeBindingContainer, ( ListAttributeSource ) attributeSource, attribute );
resolvedType = resolveListType( ( ListBinding ) attributeBinding );
} else if ( nature == PluralAttributeNature.MAP ) {
attributeBinding = bindMapAttribute( attributeBindingContainer, ( MapAttributeSource ) attributeSource, attribute );
resolvedType = resolveMapType( ( MapBinding ) attributeBinding );
} else {
throw new NotYetImplementedException( nature.toString() );
}
@ -1067,10 +1067,10 @@ public class Binder {
attributeSource.getElementSource().getNature() ) );
}
if (attributeSource instanceof ListAttributeSourceImpl) {
if ( attributeSource instanceof IndexedPluralAttributeSource ) {
bindCollectionIndex(
(IndexedPluralAttributeBinding) attributeBinding,
( (ListAttributeSourceImpl) attributeSource ).getIndexSource(),
( (IndexedPluralAttributeSource) attributeSource ).getIndexSource(),
defaultCollectionIndexJavaTypeName( reflectedCollectionJavaTypes ) );
}
@ -1133,7 +1133,30 @@ public class Binder {
createMetaAttributeContext( attributeBindingContainer, attributeSource ),
null );
}
private void bindSimpleIdentifier( final EntityBinding rootEntityBinding, final SimpleIdentifierSource identifierSource ) {
// locate the attribute binding
final BasicAttributeBinding idAttributeBinding =
( BasicAttributeBinding ) bindAttribute( rootEntityBinding, identifierSource.getIdentifierAttributeSource() );
// Configure ID generator
IdGenerator generator = identifierSource.getIdentifierGeneratorDescriptor();
if ( generator == null ) {
final Map< String, String > params = new HashMap< String, String >();
params.put( IdentifierGenerator.ENTITY_NAME, rootEntityBinding.getEntity().getName() );
generator = new IdGenerator( "default_assign_identity_generator", "assigned", params );
}
// determine the unsaved value mapping
final String unsavedValue = getIdentifierUnsavedValue( identifierSource, generator );
rootEntityBinding.getHierarchyDetails().getEntityIdentifier().bindAsSingleAttributeIdentifier(
idAttributeBinding,
generator,
unsavedValue
);
}
private SingularAttributeBinding bindSingularAttribute(
final AttributeBindingContainer attributeBindingContainer,
final SingularAttributeSource attributeSource ) {
@ -1249,7 +1272,7 @@ public class Binder {
versionAttributeSource.getUnsavedValue() == null ? "undefined" : versionAttributeSource.getUnsavedValue()
);
}
private TableSpecification createCollectionTable(
final AbstractPluralAttributeBinding pluralAttributeBinding,
final PluralAttributeSource attributeSource ) {
@ -1658,6 +1681,17 @@ public class Binder {
}
}
private Type resolveMapType( MapBinding mapBinding ) {
if ( mapBinding.getHibernateTypeDescriptor().getExplicitTypeName() != null ) {
return resolveCustomCollectionType( mapBinding );
} else {
return metadata.getTypeResolver().getTypeFactory().map(
mapBinding.getAttribute().getRole(),
mapBinding.getReferencedPropertyName(),
mapBinding.getPluralAttributeElementBinding().getPluralAttributeElementNature() == PluralAttributeElementNature.COMPOSITE );
}
}
private Type resolveSetType( SetBinding setBinding ) {
if ( setBinding.getHibernateTypeDescriptor().getExplicitTypeName() != null ) {
return resolveCustomCollectionType( setBinding );

View File

@ -177,14 +177,18 @@ public abstract class AbstractEntitySourceImpl
);
}
else if ( JaxbListElement.class.isInstance( attributeElement ) ) {
return new ListAttributeSourceImpl(
return new ListAttributeSource(
sourceMappingDocument(),
JaxbListElement.class.cast( attributeElement ),
this
);
}
else if ( JaxbMapElement.class.isInstance( attributeElement ) ) {
// todo : implement
return new MapAttributeSource(
sourceMappingDocument(),
JaxbMapElement.class.cast( attributeElement ),
this
);
}
throw new UnexpectedAttributeSourceTypeException(

View File

@ -30,7 +30,6 @@ import java.util.Map;
import org.hibernate.internal.jaxb.mapping.hbm.JaxbColumnElement;
import org.hibernate.internal.jaxb.mapping.hbm.JaxbIndexElement;
import org.hibernate.internal.jaxb.mapping.hbm.JaxbListIndexElement;
import org.hibernate.metamodel.spi.source.AttributeSourceContainer;
import org.hibernate.metamodel.spi.source.ExplicitHibernateTypeSource;
import org.hibernate.metamodel.spi.source.PluralAttributeIndexSource;
import org.hibernate.metamodel.spi.source.RelationalValueSource;
@ -38,16 +37,13 @@ import org.hibernate.metamodel.spi.source.RelationalValueSource;
/**
*
*/
public class PluralAttributeIndexSourceImpl extends AbstractHbmSourceNode implements PluralAttributeIndexSource {
public class ListAttributeIndexSource extends AbstractHbmSourceNode implements PluralAttributeIndexSource {
private final List< RelationalValueSource > valueSources;
private final ExplicitHibernateTypeSource typeSource;
private final int base;
public PluralAttributeIndexSourceImpl(
MappingDocument mappingDocument,
final JaxbListIndexElement indexElement,
final AttributeSourceContainer container ) {
public ListAttributeIndexSource( MappingDocument mappingDocument, final JaxbListIndexElement indexElement ) {
super( mappingDocument );
valueSources = Helper.buildValueSources( sourceMappingDocument(), new Helper.ValueSourcesAdapter() {
@ -85,7 +81,6 @@ public class PluralAttributeIndexSourceImpl extends AbstractHbmSourceNode implem
return areValuesIncludedInUpdateByDefault();
}
} );
typeSource = new ExplicitHibernateTypeSource() {
@Override
@ -98,21 +93,14 @@ public class PluralAttributeIndexSourceImpl extends AbstractHbmSourceNode implem
return java.util.Collections.< String, String >emptyMap();
}
};
base = Integer.parseInt( indexElement.getBase() );
}
public PluralAttributeIndexSourceImpl(
MappingDocument mappingDocument,
final JaxbIndexElement indexElement,
final AttributeSourceContainer container ) {
// TODO: What do we do with the length property?
public ListAttributeIndexSource( MappingDocument mappingDocument, final JaxbIndexElement indexElement ) {
super( mappingDocument );
valueSources = Helper.buildValueSources( sourceMappingDocument(), new Helper.ValueSourcesAdapter() {
List< JaxbColumnElement > columnElements = indexElement.getColumn() == null
? Collections.EMPTY_LIST
: Collections.singletonList( indexElement.getColumn() );
@Override
public String getColumnAttribute() {
return indexElement.getColumnAttribute();
@ -120,7 +108,7 @@ public class PluralAttributeIndexSourceImpl extends AbstractHbmSourceNode implem
@Override
public List getColumnOrFormulaElements() {
return columnElements;
return indexElement.getColumn();
}
@Override
@ -143,12 +131,11 @@ public class PluralAttributeIndexSourceImpl extends AbstractHbmSourceNode implem
return areValuesIncludedInUpdateByDefault();
}
} );
typeSource = new ExplicitHibernateTypeSource() {
@Override
public String getName() {
return "integer";
return indexElement.getType();
}
@Override
@ -156,7 +143,6 @@ public class PluralAttributeIndexSourceImpl extends AbstractHbmSourceNode implem
return java.util.Collections.< String, String >emptyMap();
}
};
base = 0;
}
@ -190,12 +176,6 @@ public class PluralAttributeIndexSourceImpl extends AbstractHbmSourceNode implem
return false;
}
/**
* {@inheritDoc}
*
* @see org.hibernate.metamodel.spi.source.PluralAttributeIndexSource#base()
*/
@Override
public int base() {
return base;
}

View File

@ -26,35 +26,36 @@ package org.hibernate.metamodel.internal.source.hbm;
import org.hibernate.internal.jaxb.mapping.hbm.JaxbListElement;
import org.hibernate.internal.jaxb.mapping.hbm.JaxbListIndexElement;
import org.hibernate.metamodel.spi.source.AttributeSourceContainer;
import org.hibernate.metamodel.spi.source.PluralAttributeIndexSource;
import org.hibernate.metamodel.spi.source.IndexedPluralAttributeSource;
import org.hibernate.metamodel.spi.source.PluralAttributeNature;
/**
*
*/
public class ListAttributeSourceImpl extends AbstractPluralAttributeSourceImpl {
public class ListAttributeSource extends AbstractPluralAttributeSourceImpl implements IndexedPluralAttributeSource {
private final PluralAttributeIndexSource indexSource;
private final ListAttributeIndexSource indexSource;
/**
* @param sourceMappingDocument
* @param listElement
* @param container
*/
public ListAttributeSourceImpl(
public ListAttributeSource(
MappingDocument sourceMappingDocument,
JaxbListElement listElement,
AttributeSourceContainer container ) {
super( sourceMappingDocument, listElement, container );
JaxbListIndexElement listIndexElement = listElement.getListIndex();
if ( listIndexElement == null ) {
this.indexSource = new PluralAttributeIndexSourceImpl( sourceMappingDocument(), listElement.getIndex(), container );
this.indexSource = new ListAttributeIndexSource( sourceMappingDocument(), listElement.getIndex() );
} else {
this.indexSource = new PluralAttributeIndexSourceImpl( sourceMappingDocument(), listIndexElement, container );
this.indexSource = new ListAttributeIndexSource( sourceMappingDocument(), listIndexElement );
}
}
public PluralAttributeIndexSource getIndexSource() {
@Override
public ListAttributeIndexSource getIndexSource() {
return indexSource;
}

View File

@ -0,0 +1,151 @@
/*
* 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.internal.source.hbm;
import java.util.List;
import java.util.Map;
import org.hibernate.internal.jaxb.mapping.hbm.JaxbMapElement.JaxbMapKey;
import org.hibernate.metamodel.spi.source.ExplicitHibernateTypeSource;
import org.hibernate.metamodel.spi.source.PluralAttributeIndexSource;
import org.hibernate.metamodel.spi.source.RelationalValueSource;
/**
*
*/
public class MapAttributeIndexSource extends AbstractHbmSourceNode implements PluralAttributeIndexSource {
private final List< RelationalValueSource > valueSources;
private final ExplicitHibernateTypeSource typeSource;
/**
* @param sourceMappingDocument
*/
// TODO: What do we do with the length property?
public MapAttributeIndexSource( MappingDocument sourceMappingDocument, final JaxbMapKey mapKey ) {
super( sourceMappingDocument );
valueSources = Helper.buildValueSources( sourceMappingDocument(), new Helper.ValueSourcesAdapter() {
@Override
public String getColumnAttribute() {
return mapKey.getColumn();
}
@Override
public List getColumnOrFormulaElements() {
return mapKey.getColumnOrFormula();
}
@Override
public String getContainingTableName() {
return null;
}
@Override
public String getFormulaAttribute() {
return mapKey.getFormula();
}
@Override
public boolean isIncludedInInsertByDefault() {
return areValuesIncludedInInsertByDefault();
}
@Override
public boolean isIncludedInUpdateByDefault() {
return areValuesIncludedInUpdateByDefault();
}
} );
this.typeSource = new ExplicitHibernateTypeSource() {
@Override
public String getName() {
if ( mapKey.getTypeAttribute() != null ) {
return mapKey.getTypeAttribute();
}
if ( mapKey.getType() != null ) {
return mapKey.getType().getName();
}
return null;
}
@Override
public Map< String, String > getParameters() {
return mapKey.getType() != null
? Helper.extractParameters( mapKey.getType().getParam() )
: java.util.Collections.< String, String >emptyMap();
}
};
}
/**
* {@inheritDoc}
*
* @see org.hibernate.metamodel.spi.source.ColumnBindingDefaults#areValuesIncludedInInsertByDefault()
*/
@Override
public boolean areValuesIncludedInInsertByDefault() {
return true;
}
/**
* {@inheritDoc}
*
* @see org.hibernate.metamodel.spi.source.ColumnBindingDefaults#areValuesIncludedInUpdateByDefault()
*/
@Override
public boolean areValuesIncludedInUpdateByDefault() {
return true;
}
/**
* {@inheritDoc}
*
* @see org.hibernate.metamodel.spi.source.ColumnBindingDefaults#areValuesNullableByDefault()
*/
@Override
public boolean areValuesNullableByDefault() {
return false;
}
/**
* {@inheritDoc}
*
* @see org.hibernate.metamodel.spi.source.PluralAttributeIndexSource#explicitHibernateTypeSource()
*/
@Override
public ExplicitHibernateTypeSource explicitHibernateTypeSource() {
return typeSource;
}
/**
* {@inheritDoc}
*
* @see org.hibernate.metamodel.spi.source.RelationalValueSourceContainer#relationalValueSources()
*/
@Override
public List< RelationalValueSource > relationalValueSources() {
return valueSources;
}
}

View File

@ -0,0 +1,78 @@
/*
* 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.internal.source.hbm;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.internal.jaxb.mapping.hbm.JaxbMapElement;
import org.hibernate.internal.jaxb.mapping.hbm.JaxbMapElement.JaxbMapKey;
import org.hibernate.metamodel.spi.source.AttributeSourceContainer;
import org.hibernate.metamodel.spi.source.IndexedPluralAttributeSource;
import org.hibernate.metamodel.spi.source.PluralAttributeNature;
/**
*
*/
public class MapAttributeSource extends AbstractPluralAttributeSourceImpl implements IndexedPluralAttributeSource {
private final MapAttributeIndexSource indexSource;
/**
* @param sourceMappingDocument
* @param pluralAttributeElement
* @param container
*/
public MapAttributeSource(
MappingDocument sourceMappingDocument,
JaxbMapElement mapElement,
AttributeSourceContainer container ) {
super( sourceMappingDocument, mapElement, container );
JaxbMapKey mapKey = mapElement.getMapKey();
if ( mapKey == null ) {
throw new NotYetImplementedException(
"<map-key-many-to-many>, <composite-map-key>, <index>, <composite-index>, <index-many-to-many>, and <index-many-to-any>" );
} else {
this.indexSource = new MapAttributeIndexSource( sourceMappingDocument(), mapKey );
}
}
@Override
public MapAttributeIndexSource getIndexSource() {
return indexSource;
}
@Override
public JaxbMapElement getPluralAttributeElement() {
return ( JaxbMapElement ) super.getPluralAttributeElement();
}
/**
* {@inheritDoc}
*
* @see org.hibernate.metamodel.spi.source.PluralAttributeSource#getPluralAttributeNature()
*/
@Override
public PluralAttributeNature getPluralAttributeNature() {
return PluralAttributeNature.MAP;
}
}

View File

@ -157,7 +157,7 @@ public interface AttributeBindingContainer {
MetaAttributeContext metaAttributeContext);
/**
* Factory method for bag attribute bindings.
* Factory method for list attribute bindings.
*
* @param attribute The attribute for which to make a binding.
* @param nature The nature of the collection elements.
@ -181,7 +181,29 @@ public interface AttributeBindingContainer {
int base );
/**
* Factory method for bag attribute bindings.
* Factory method for map attribute bindings.
*
* @param attribute The attribute for which to make a binding.
* @param nature The nature of the collection elements.
* @param referencedAttributeBinding
* @param propertyAccessorName
* @param includedInOptimisticLocking
* @param lazy
* @param metaAttributeContext
*
* @return The attribute binding instance.
*/
public MapBinding makeMapAttributeBinding(
PluralAttribute attribute,
PluralAttributeElementNature nature,
SingularAttributeBinding referencedAttributeBinding,
String propertyAccessorName,
boolean includedInOptimisticLocking,
boolean lazy,
MetaAttributeContext metaAttributeContext );
/**
* Factory method for set attribute bindings.
*
* @param attribute The attribute for which to make a binding.
* @param nature The nature of the collection elements.

View File

@ -260,6 +260,29 @@ public class CompositeAttributeBinding
return binding;
}
@Override
public MapBinding makeMapAttributeBinding(
PluralAttribute attribute,
PluralAttributeElementNature nature,
SingularAttributeBinding referencedAttributeBinding,
String propertyAccessorName,
boolean includedInOptimisticLocking,
boolean lazy,
MetaAttributeContext metaAttributeContext ) {
Helper.checkPluralAttributeNature( attribute, PluralAttributeNature.MAP );
final MapBinding binding = new MapBinding(
this,
attribute,
nature,
referencedAttributeBinding,
propertyAccessorName,
includedInOptimisticLocking,
lazy,
metaAttributeContext );
registerAttributeBinding( attribute.getName(), binding );
return binding;
}
@Override
public SetBinding makeSetAttributeBinding(
PluralAttribute attribute,

View File

@ -596,6 +596,29 @@ public class EntityBinding implements AttributeBindingContainer {
return binding;
}
@Override
public MapBinding makeMapAttributeBinding(
PluralAttribute attribute,
PluralAttributeElementNature nature,
SingularAttributeBinding referencedAttributeBinding,
String propertyAccessorName,
boolean includedInOptimisticLocking,
boolean lazy,
MetaAttributeContext metaAttributeContext ) {
Helper.checkPluralAttributeNature( attribute, PluralAttributeNature.MAP );
final MapBinding binding = new MapBinding(
this,
attribute,
nature,
referencedAttributeBinding,
propertyAccessorName,
includedInOptimisticLocking,
lazy,
metaAttributeContext );
registerAttributeBinding( attribute.getName(), binding );
return binding;
}
@Override
public SetBinding makeSetAttributeBinding(
PluralAttribute attribute,

View File

@ -31,8 +31,8 @@ import org.hibernate.metamodel.spi.source.MetaAttributeContext;
*/
public class ListBinding extends AbstractPluralAttributeBinding implements IndexedPluralAttributeBinding {
private PluralAttributeIndexBinding pluralAttributeIndexBinding;
private int base;
private final PluralAttributeIndexBinding pluralAttributeIndexBinding;
private final int base;
public ListBinding(
AttributeBindingContainer container,
@ -53,7 +53,7 @@ public class ListBinding extends AbstractPluralAttributeBinding implements Index
includedInOptimisticLocking,
isLazy,
metaAttributeContext );
this.pluralAttributeIndexBinding = new BasicPluralAttributeIndexBinding( this );
pluralAttributeIndexBinding = new BasicPluralAttributeIndexBinding( this );
this.base = base;
}

View File

@ -0,0 +1,67 @@
/*
* 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.spi.binding;
import org.hibernate.metamodel.spi.domain.PluralAttribute;
import org.hibernate.metamodel.spi.source.MetaAttributeContext;
/**
*
*/
public class MapBinding extends AbstractPluralAttributeBinding implements IndexedPluralAttributeBinding {
private final PluralAttributeIndexBinding pluralAttributeIndexBinding;
public MapBinding(
AttributeBindingContainer container,
PluralAttribute attribute,
PluralAttributeElementNature pluralAttributeElementNature,
SingularAttributeBinding referencedAttributeBinding,
String propertyAccessorName,
boolean includedInOptimisticLocking,
boolean isLazy,
MetaAttributeContext metaAttributeContext ) {
super(
container,
attribute,
pluralAttributeElementNature,
referencedAttributeBinding,
propertyAccessorName,
includedInOptimisticLocking,
isLazy,
metaAttributeContext );
pluralAttributeIndexBinding = new BasicPluralAttributeIndexBinding( this );
}
/**
* {@inheritDoc}
*
* @see org.hibernate.metamodel.spi.binding.IndexedPluralAttributeBinding#getPluralAttributeIndexBinding()
*/
@Override
public PluralAttributeIndexBinding getPluralAttributeIndexBinding() {
return pluralAttributeIndexBinding;
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.spi.source;
/**
*
*/
public interface IndexedPluralAttributeSource extends PluralAttributeSource {
PluralAttributeIndexSource getIndexSource();
}

View File

@ -28,7 +28,5 @@ package org.hibernate.metamodel.spi.source;
*/
public interface PluralAttributeIndexSource extends RelationalValueSourceContainer {
int base();
ExplicitHibernateTypeSource explicitHibernateTypeSource();
}

View File

@ -70,7 +70,6 @@ import org.hibernate.jdbc.Expectation;
import org.hibernate.jdbc.Expectations;
import org.hibernate.loader.collection.CollectionInitializer;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Formula;
import org.hibernate.mapping.IdentifierCollection;
import org.hibernate.mapping.IndexedCollection;
@ -87,6 +86,7 @@ import org.hibernate.metamodel.spi.binding.PluralAttributeIndexBinding;
import org.hibernate.metamodel.spi.binding.PluralAttributeKeyBinding;
import org.hibernate.metamodel.spi.binding.RelationalValueBinding;
import org.hibernate.metamodel.spi.domain.PluralAttributeNature;
import org.hibernate.metamodel.spi.relational.Column;
import org.hibernate.metamodel.spi.relational.DerivedValue;
import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.metamodel.spi.relational.Value;
@ -312,7 +312,7 @@ public abstract class AbstractCollectionPersister
int k = 0;
while ( iter.hasNext() ) {
// NativeSQL: collect key column and auto-aliases
Column col = ( (Column) iter.next() );
org.hibernate.mapping.Column col = ( (org.hibernate.mapping.Column) iter.next() );
keyColumnNames[k] = col.getQuotedName( dialect );
keyColumnAliases[k] = col.getAlias( dialect, collection.getOwner().getRootTable() );
k++;
@ -360,7 +360,7 @@ public abstract class AbstractCollectionPersister
elementFormulas[j] = form.getFormula();
}
else {
Column col = (Column) selectable;
org.hibernate.mapping.Column col = (org.hibernate.mapping.Column) selectable;
elementColumnNames[j] = col.getQuotedName( dialect );
elementColumnWriters[j] = col.getWriteExpr();
elementColumnReaders[j] = col.getReadExpr( dialect );
@ -409,7 +409,7 @@ public abstract class AbstractCollectionPersister
hasFormula = true;
}
else {
Column indexCol = (Column) s;
org.hibernate.mapping.Column indexCol = (org.hibernate.mapping.Column) s;
indexColumnNames[i] = indexCol.getQuotedName( dialect );
indexColumnIsSettable[i] = true;
}
@ -442,7 +442,7 @@ public abstract class AbstractCollectionPersister
IdentifierCollection idColl = (IdentifierCollection) collection;
identifierType = idColl.getIdentifier().getType();
iter = idColl.getIdentifier().getColumnIterator();
Column col = (Column) iter.next();
org.hibernate.mapping.Column col = (org.hibernate.mapping.Column) iter.next();
identifierColumnName = col.getQuotedName( dialect );
identifierColumnAlias = col.getAlias( dialect );
// unquotedIdentifierColumnName = identifierColumnAlias;
@ -711,7 +711,7 @@ public abstract class AbstractCollectionPersister
keyColumnNames = new String[keySpan];
keyColumnAliases = new String[keySpan];
int k = 0;
for ( org.hibernate.metamodel.spi.relational.Column keyColumn : keyBinding.getForeignKey().getSourceColumns() ) {
for ( Column keyColumn : keyBinding.getForeignKey().getSourceColumns() ) {
// NativeSQL: collect key column and auto-aliases
keyColumnNames[k] = keyColumn.getColumnName().encloseInQuotesIfQuoted( dialect );
// TODO: does the owner root table need to be in alias?
@ -765,7 +765,7 @@ public abstract class AbstractCollectionPersister
elementFormulas[j] = form.getExpression();
}
else {
org.hibernate.metamodel.spi.relational.Column col = (org.hibernate.metamodel.spi.relational.Column) value;
Column col = (Column) value;
elementColumnNames[j] = col.getColumnName().encloseInQuotesIfQuoted( dialect );
elementColumnWriters[j] = col.getWriteFragment() == null ? "?" : col.getWriteFragment();
elementColumnReaders[j] = col.getReadFragment() == null ?
@ -803,12 +803,23 @@ public abstract class AbstractCollectionPersister
PluralAttributeIndexBinding indexBinding = indexedBinding.getPluralAttributeIndexBinding();
indexType = indexBinding.getHibernateTypeDescriptor().getResolvedTypeMapping();
baseIndex = indexBinding instanceof ListBinding ? ( ( ListBinding ) indexBinding ).base() : 0;
Column column = (Column) indexBinding.getIndexRelationalValue();
indexColumnNames = new String[] { column.getQuotedName( dialect ) };
indexColumnAliases = new String[] { column.getAlias( dialect ) };
indexFormulaTemplates = new String[1];
indexFormulas = new String[1];
indexColumnIsSettable = new boolean[] { true };
// TODO: Deal with multiple columns/formulas
indexColumnAliases = new String[ 1 ];
indexColumnNames = new String[ 1 ];
indexColumnIsSettable = new boolean[ 1 ];
indexFormulaTemplates = new String[ 1 ];
indexFormulas = new String[ 1 ];
Value value = indexBinding.getIndexRelationalValue();
indexColumnAliases[ 0 ] = value.getAlias( dialect );
if ( value instanceof Column ) {
indexColumnIsSettable[ 0 ] = true;
Column column = ( Column ) value;
indexColumnNames[ 0 ] = column.getColumnName().encloseInQuotesIfQuoted( dialect );
} else {
DerivedValue derivedValue = ( DerivedValue ) value;
indexFormulaTemplates[ 0 ] = getTemplateFromString( derivedValue.getExpression(), factory);
indexFormulas[ 0 ] = derivedValue.getExpression();
}
} else {
indexColumnIsSettable = null;
indexFormulaTemplates = null;

View File

@ -32,6 +32,12 @@
<element column="list_stuff" type="string"/>
</list>
<map name="theMap">
<key column="pid"/>
<map-key column="map_key" type="string"/>
<element column="map_value" type="string"/>
</map>
</class>
</hibernate-mapping>

View File

@ -25,8 +25,10 @@ package org.hibernate.metamodel.spi.binding;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.ElementCollection;
@ -41,15 +43,16 @@ import javax.persistence.Id;
public class EntityWithBasicCollections {
private Long id;
private String name;
private Collection<String> theBag = new ArrayList<String>();
private Set<String> theSet = new HashSet<String>();
private Set<Integer> thePropertyRefSet = new HashSet<Integer>();
private List<String> theList = new ArrayList<String>();
private Collection< String > theBag = new ArrayList< String >();
private Set< String > theSet = new HashSet< String >();
private Set< Integer > thePropertyRefSet = new HashSet< Integer >();
private List< String > theList = new ArrayList< String >();
private Map< String, String > theMap = new HashMap< String, String >();
public EntityWithBasicCollections() {
}
public EntityWithBasicCollections(String name) {
public EntityWithBasicCollections( String name ) {
this.name = name;
}
@ -58,7 +61,7 @@ public class EntityWithBasicCollections {
return id;
}
public void setId(Long id) {
public void setId( Long id ) {
this.id = id;
}
@ -66,43 +69,52 @@ public class EntityWithBasicCollections {
return name;
}
public void setName(String name) {
public void setName( String name ) {
this.name = name;
}
@ElementCollection
public Collection<String> getTheBag() {
public Collection< String > getTheBag() {
return theBag;
}
public void setTheBag(Collection<String> theBag) {
public void setTheBag( Collection< String > theBag ) {
this.theBag = theBag;
}
@ElementCollection
public Set<String> getTheSet() {
public Set< String > getTheSet() {
return theSet;
}
public void setTheSet(Set<String> theSet) {
public void setTheSet( Set< String > theSet ) {
this.theSet = theSet;
}
@ElementCollection
public Set<Integer> getThePropertyRefSet() {
public Set< Integer > getThePropertyRefSet() {
return thePropertyRefSet;
}
public void setThePropertyRefSet(Set<Integer> thePropertyRefSet) {
public void setThePropertyRefSet( Set< Integer > thePropertyRefSet ) {
this.thePropertyRefSet = thePropertyRefSet;
}
@ElementCollection
public List<String> getTheList() {
public List< String > getTheList() {
return theList;
}
public void setTheList(List<String> theList) {
public void setTheList( List< String > theList ) {
this.theList = theList;
}
@ElementCollection
public Map< String, String > getTheMap() {
return theMap;
}
public void setTheMap( Map< String, String > theMap ) {
this.theMap = theMap;
}
}