HHH-7888 - Bind @OrderBy with empty value

This commit is contained in:
Strong Liu 2012-12-28 03:39:51 +08:00
parent 288823d2dd
commit 2d43576045
17 changed files with 295 additions and 159 deletions

View File

@ -1065,7 +1065,7 @@ public abstract class CollectionBinder {
TableBinder associationTableBinder,
XProperty property,
PropertyHolder parentPropertyHolder,
String hqlOrderBy,
final String hqlOrderBy,
Mappings mappings) throws MappingException {
PersistentClass collectionEntity = (PersistentClass) persistentClasses.get( collType.getName() );
@ -1286,7 +1286,6 @@ public abstract class CollectionBinder {
collValue.setElement( component );
if ( StringHelper.isNotEmpty( hqlOrderBy ) ) {
String path = collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName();
String orderBy = adjustUserSuppliedValueCollectionOrderingFragment( hqlOrderBy );
if ( orderBy != null ) {
collValue.setOrderBy( orderBy );

View File

@ -156,4 +156,20 @@ public final class CollectionHelper {
public static <T> List<T> createEmptyList(Class<T> elementClass) {
return Collections.emptyList();
}
public static boolean isCollectionOrArray(Class clazz) {
if ( clazz == null ) {
return false;
}
if ( Collection.class.isAssignableFrom( clazz ) ) {
return true;
}
if ( Map.class.isAssignableFrom( clazz ) ) {
return true;
}
// if ( clazz.isArray() ) {
// return true;
// }
return false;
}
}

View File

@ -1980,23 +1980,7 @@ public class Binder {
if ( Orderable.class.isInstance( attributeSource ) ) {
final Orderable orderable = (Orderable) attributeSource;
if ( orderable.isOrdered() ) {
String orderBy = orderable.getOrder();
if ( orderBy.equals( "" ) ) {
PrimaryKey pk = attributeBinding.getPluralAttributeKeyBinding()
.getReferencedAttributeBinding()
.getContainer()
.seekEntityBinding()
.getPrimaryTable()
.getPrimaryKey();
List<Column> pkColumns = pk.getColumns();
StringBuffer sb = new StringBuffer();
for ( final Column column : pkColumns ) {
sb.append( column.getColumnName().getText() );
sb.append( " asc ," );
}
orderBy = sb.substring( 0, sb.length() - 2 );
}
attributeBinding.setOrderBy( orderBy );
attributeBinding.setOrderBy( orderable.getOrder() );
}
}
@ -2250,47 +2234,52 @@ public class Binder {
}
}
/**
* TODO : It is really confusing that we have so many different <tt>natures</tt>
*/
private void bindCollectionTablePrimaryKey(
final AbstractPluralAttributeBinding attributeBinding,
final PluralAttributeSource attributeSource) {
PluralAttributeSource.Nature pluralAttributeNature = attributeSource.getNature();
if ( attributeSource.getElementSource().getNature() == PluralAttributeElementSource.Nature.ONE_TO_MANY
|| pluralAttributeNature == PluralAttributeSource.Nature.BAG ) {
final PluralAttributeSource.Nature pluralAttributeSourceNature = attributeSource.getNature();
final PluralAttributeElementSource.Nature pluralElementSourceNature = attributeSource.getElementSource().getNature();
final PluralAttributeElementBinding.Nature pluralElementBindingNature = attributeBinding.getPluralAttributeElementBinding().getNature();
//TODO what is this case? it would be really good to add a comment
if ( pluralElementSourceNature == PluralAttributeElementSource.Nature.ONE_TO_MANY
|| pluralAttributeSourceNature == PluralAttributeSource.Nature.BAG ) {
return;
}
if ( attributeBinding.getPluralAttributeElementBinding()
.getNature() == PluralAttributeElementBinding.Nature.BASIC ) {
if ( pluralAttributeNature == PluralAttributeSource.Nature.SET ) {
bindBasicSetCollectionTablePrimaryKey( (SetBinding) attributeBinding );
}
else if (
pluralAttributeNature == PluralAttributeSource.Nature.LIST
|| pluralAttributeNature == PluralAttributeSource.Nature.MAP
|| pluralAttributeNature == PluralAttributeSource.Nature.ARRAY ) {
bindIndexedCollectionTablePrimaryKey( (IndexedPluralAttributeBinding) attributeBinding );
}
else {
throw new NotYetImplementedException(
String.format( "%s of basic elements is not supported yet.", pluralAttributeNature )
);
if ( pluralElementBindingNature == PluralAttributeElementBinding.Nature.BASIC ) {
switch ( pluralAttributeSourceNature ) {
case SET:
bindBasicSetCollectionTablePrimaryKey( (SetBinding) attributeBinding );
break;
case LIST:
case MAP:
case ARRAY:
bindIndexedCollectionTablePrimaryKey( (IndexedPluralAttributeBinding) attributeBinding );
break;
default:
throw new NotYetImplementedException(
String.format( "%s of basic elements is not supported yet.", pluralAttributeSourceNature )
);
}
}
else if ( attributeBinding.getPluralAttributeElementBinding()
.getNature() == PluralAttributeElementBinding.Nature.MANY_TO_MANY ) {
else if ( pluralElementBindingNature == PluralAttributeElementBinding.Nature.MANY_TO_MANY ) {
if ( !attributeBinding.getPluralAttributeKeyBinding().isInverse() ) {
if ( pluralAttributeNature == PluralAttributeSource.Nature.SET ) {
bindSetCollectionTablePrimaryKey( (SetBinding) attributeBinding );
}
else if (
pluralAttributeNature == PluralAttributeSource.Nature.LIST
|| pluralAttributeNature == PluralAttributeSource.Nature.MAP
|| pluralAttributeNature == PluralAttributeSource.Nature.ARRAY ) {
bindIndexedCollectionTablePrimaryKey( (IndexedPluralAttributeBinding) attributeBinding );
}
else {
throw new NotYetImplementedException(
String.format( "Many-to-many %s is not supported yet.", pluralAttributeNature )
);
switch ( pluralAttributeSourceNature ) {
case SET:
bindSetCollectionTablePrimaryKey( (SetBinding) attributeBinding );
break;
case LIST:
case MAP:
case ARRAY:
bindIndexedCollectionTablePrimaryKey( (IndexedPluralAttributeBinding) attributeBinding );
break;
default:
throw new NotYetImplementedException(
String.format( "Many-to-many %s is not supported yet.", pluralAttributeSourceNature )
);
}
}
}

View File

@ -144,8 +144,8 @@ public class ComponentAttributeSourceImpl implements ComponentAttributeSource {
}
for ( AssociationAttribute associationAttribute : embeddableClass.getAssociationAttributes() ) {
associationAttribute.setNaturalIdMutability( embeddableClass.getNaturalIdMutability() );
attributeList.add( new ToOneAttributeSourceImpl( associationAttribute ) );
}
SourceHelper.resolveAssociationAttributes( embeddableClass, attributeList );
return Collections.unmodifiableList( attributeList );
}
}

View File

@ -31,8 +31,8 @@ import org.hibernate.internal.util.ValueHolder;
import org.hibernate.metamodel.internal.source.annotations.attribute.AssociationAttribute;
import org.hibernate.metamodel.internal.source.annotations.attribute.AttributeOverride;
import org.hibernate.metamodel.internal.source.annotations.attribute.BasicAttribute;
import org.hibernate.metamodel.internal.source.annotations.entity.ConfiguredClass;
import org.hibernate.metamodel.internal.source.annotations.entity.EmbeddableClass;
import org.hibernate.metamodel.internal.source.annotations.entity.EntityClass;
import org.hibernate.metamodel.spi.binding.CascadeType;
import org.hibernate.metamodel.spi.source.AttributeSource;
import org.hibernate.metamodel.spi.source.CompositePluralAttributeElementSource;
@ -47,7 +47,7 @@ public class CompositePluralAttributeElementSourceImpl implements CompositePlura
private static final String PATH_SEPARATOR = ".";
private final AssociationAttribute associationAttribute;
private final EntityClass entityClass;
private final ConfiguredClass entityClass;
private List<AttributeSource> attributeSources
= new ArrayList<AttributeSource>();
@ -56,7 +56,7 @@ public class CompositePluralAttributeElementSourceImpl implements CompositePlura
public CompositePluralAttributeElementSourceImpl(
AssociationAttribute associationAttribute,
EntityClass rootEntityClass ) {
ConfiguredClass rootEntityClass ) {
this.associationAttribute = associationAttribute;
this.entityClass = rootEntityClass;
@ -152,8 +152,8 @@ public class CompositePluralAttributeElementSourceImpl implements CompositePlura
}
for ( AssociationAttribute associationAttribute : embeddableClass.getAssociationAttributes() ) {
associationAttribute.setNaturalIdMutability( embeddableClass.getNaturalIdMutability() );
attributeSources.add( new ToOneAttributeSourceImpl( associationAttribute ) );
}
SourceHelper.resolveAssociationAttributes( embeddableClass, attributeSources );
}
private Map<String, AttributeOverride> createAggregatedOverrideMap(

View File

@ -32,16 +32,12 @@ import java.util.Set;
import org.hibernate.AnnotationException;
import org.hibernate.MappingException;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.jaxb.spi.Origin;
import org.hibernate.metamodel.internal.source.annotations.attribute.AssociationAttribute;
import org.hibernate.metamodel.internal.source.annotations.attribute.AttributeOverride;
import org.hibernate.metamodel.internal.source.annotations.attribute.BasicAttribute;
import org.hibernate.metamodel.internal.source.annotations.attribute.PluralAssociationAttribute;
import org.hibernate.metamodel.internal.source.annotations.entity.EmbeddableClass;
import org.hibernate.metamodel.internal.source.annotations.entity.EntityClass;
import org.hibernate.metamodel.internal.source.annotations.entity.RootEntityClass;
import org.hibernate.metamodel.internal.source.annotations.util.HibernateDotNames;
import org.hibernate.metamodel.internal.source.annotations.util.JPADotNames;
import org.hibernate.metamodel.internal.source.annotations.util.JandexHelper;
@ -53,7 +49,6 @@ import org.hibernate.metamodel.spi.source.EntitySource;
import org.hibernate.metamodel.spi.source.JpaCallbackSource;
import org.hibernate.metamodel.spi.source.LocalBindingContext;
import org.hibernate.metamodel.spi.source.MetaAttributeSource;
import org.hibernate.metamodel.spi.source.PluralAttributeSource;
import org.hibernate.metamodel.spi.source.PrimaryKeyJoinColumnSource;
import org.hibernate.metamodel.spi.source.SecondaryTableSource;
import org.hibernate.metamodel.spi.source.SubclassEntitySource;
@ -229,32 +224,7 @@ public class EntitySourceImpl implements EntitySource {
)
);
}
for ( AssociationAttribute associationAttribute : entityClass.getAssociationAttributes() ) {
switch ( associationAttribute.getNature() ) {
case ONE_TO_ONE:
case MANY_TO_ONE: {
attributeList.add( new ToOneAttributeSourceImpl( associationAttribute ) );
break;
}
case MANY_TO_MANY:
case ONE_TO_MANY:
case ELEMENT_COLLECTION_BASIC:
case ELEMENT_COLLECTION_EMBEDDABLE: {
PluralAssociationAttribute pluralAssociationAttribute = (PluralAssociationAttribute) associationAttribute;
PluralAttributeSource.Nature pluralAttributeNature = pluralAssociationAttribute.getPluralAttributeNature();
AttributeSource source = pluralAssociationAttribute.isIndexed() ?
new IndexedPluralAttributeSourceImpl( pluralAssociationAttribute, entityClass )
: new PluralAttributeSourceImpl( pluralAssociationAttribute, entityClass );
attributeList.add( source );
break;
}
default: {
throw new NotYetImplementedException();
}
}
}
SourceHelper.resolveAssociationAttributes( entityClass, attributeList );
return attributeList;
}

View File

@ -4,6 +4,7 @@ import java.util.EnumSet;
import org.hibernate.metamodel.internal.source.annotations.attribute.MappedAttribute;
import org.hibernate.metamodel.internal.source.annotations.attribute.PluralAssociationAttribute;
import org.hibernate.metamodel.internal.source.annotations.entity.ConfiguredClass;
import org.hibernate.metamodel.internal.source.annotations.entity.EntityClass;
import org.hibernate.metamodel.spi.source.IndexedPluralAttributeSource;
import org.hibernate.metamodel.spi.source.MappingException;
@ -15,16 +16,16 @@ import org.hibernate.metamodel.spi.source.PluralAttributeIndexSource;
public class IndexedPluralAttributeSourceImpl extends PluralAttributeSourceImpl
implements IndexedPluralAttributeSource {
private final PluralAttributeIndexSource indexSource;
private final static EnumSet<MappedAttribute.Nature> validNatures = EnumSet.of(
private final static EnumSet<MappedAttribute.Nature> VALID_NATURES = EnumSet.of(
MappedAttribute.Nature.MANY_TO_MANY,
MappedAttribute.Nature.ONE_TO_MANY,
MappedAttribute.Nature.ELEMENT_COLLECTION_BASIC,
MappedAttribute.Nature.ELEMENT_COLLECTION_EMBEDDABLE);
public IndexedPluralAttributeSourceImpl(PluralAssociationAttribute attribute,
EntityClass entityClass ) {
ConfiguredClass entityClass ) {
super( attribute, entityClass );
if ( !validNatures.contains( attribute.getNature() ) ) {
if ( !VALID_NATURES.contains( attribute.getNature() ) ) {
throw new MappingException(
"Indexed column could be only mapped on the MANY side",
attribute.getContext().getOrigin()

View File

@ -24,9 +24,6 @@
package org.hibernate.metamodel.internal.source.annotations;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jboss.jandex.AnnotationInstance;
@ -35,8 +32,8 @@ import org.hibernate.engine.FetchTiming;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.ValueHolder;
import org.hibernate.metamodel.internal.source.annotations.attribute.PluralAssociationAttribute;
import org.hibernate.metamodel.internal.source.annotations.entity.ConfiguredClass;
import org.hibernate.metamodel.internal.source.annotations.entity.EntityClass;
import org.hibernate.metamodel.internal.source.annotations.entity.RootEntityClass;
import org.hibernate.metamodel.spi.binding.Caching;
import org.hibernate.metamodel.spi.binding.CustomSQL;
import org.hibernate.metamodel.spi.source.ExplicitHibernateTypeSource;
@ -61,7 +58,7 @@ public class PluralAttributeSourceImpl implements PluralAttributeSource, Orderab
public PluralAttributeSourceImpl(
final PluralAssociationAttribute associationAttribute,
final EntityClass entityClass ) {
final ConfiguredClass entityClass ) {
this.associationAttribute = associationAttribute;
this.keySource = new PluralAttributeKeySourceImpl( associationAttribute );
this.typeSource = new ExplicitHibernateTypeSourceImpl( associationAttribute );
@ -91,7 +88,7 @@ public class PluralAttributeSourceImpl implements PluralAttributeSource, Orderab
}
}
private static PluralAttributeElementSource determineElementSource(PluralAssociationAttribute associationAttribute, EntityClass entityClass) {
private static PluralAttributeElementSource determineElementSource(PluralAssociationAttribute associationAttribute, ConfiguredClass entityClass) {
switch ( associationAttribute.getNature() ) {
case MANY_TO_MANY:
return new ManyToManyPluralAttributeElementSourceImpl( associationAttribute );
@ -222,7 +219,7 @@ public class PluralAttributeSourceImpl implements PluralAttributeSource, Orderab
@Override
public boolean isOrdered() {
return getOrder() != null;
return StringHelper.isNotEmpty( getOrder() );
}
@Override

View File

@ -0,0 +1,69 @@
/*
* 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.annotations;
import java.util.List;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.metamodel.internal.source.annotations.attribute.AssociationAttribute;
import org.hibernate.metamodel.internal.source.annotations.attribute.PluralAssociationAttribute;
import org.hibernate.metamodel.internal.source.annotations.entity.ConfiguredClass;
import org.hibernate.metamodel.spi.source.AttributeSource;
/**
* @author Strong Liu <stliu@hibernate.org>
*/
public class SourceHelper {
/**
* Bind association attributes within {@param configuredClass} to the proper source impl based on its nature.
*
* @param configuredClass The holder of association attributes.
* @param attributeList Attribute source container, can't be <code>null</code>.
*/
public static void resolveAssociationAttributes(ConfiguredClass configuredClass, List<AttributeSource> attributeList) {
for ( AssociationAttribute associationAttribute : configuredClass.getAssociationAttributes() ) {
switch ( associationAttribute.getNature() ) {
case ONE_TO_ONE:
case MANY_TO_ONE: {
attributeList.add( new ToOneAttributeSourceImpl( associationAttribute ) );
break;
}
case MANY_TO_MANY:
case ONE_TO_MANY:
case ELEMENT_COLLECTION_BASIC:
case ELEMENT_COLLECTION_EMBEDDABLE: {
PluralAssociationAttribute pluralAssociationAttribute = (PluralAssociationAttribute) associationAttribute;
AttributeSource source = pluralAssociationAttribute.isIndexed() ?
new IndexedPluralAttributeSourceImpl( pluralAssociationAttribute, configuredClass )
: new PluralAttributeSourceImpl( pluralAssociationAttribute, configuredClass );
attributeList.add( source );
break;
}
default: {
throw new NotYetImplementedException();
}
}
}
}
}

View File

@ -57,6 +57,7 @@ public class ToOneAttributeSourceImpl extends SingularAttributeSourceImpl implem
private final Set<CascadeStyle> cascadeStyles;
public ToOneAttributeSourceImpl(AssociationAttribute associationAttribute) {
super( associationAttribute );
this.associationAttribute = associationAttribute;
this.cascadeStyles = EnumConversionHelper.cascadeTypeToCascadeStyleSet(
@ -75,9 +76,8 @@ public class ToOneAttributeSourceImpl extends SingularAttributeSourceImpl implem
throw new NotYetImplementedException( "One-to-one using annotations is not supported yet." );
}
else {
throw new AssertionError(
"Wrong attribute nature for toOne attribute: " + associationAttribute.getNature()
);
throw new AssertionError(String.format( "Wrong attribute nature[%s] for toOne attribute: %s",
associationAttribute.getNature(), associationAttribute.getRole() ));
}
}

View File

@ -49,12 +49,16 @@ import org.hibernate.metamodel.internal.source.annotations.util.EnumConversionHe
import org.hibernate.metamodel.internal.source.annotations.util.HibernateDotNames;
import org.hibernate.metamodel.internal.source.annotations.util.JPADotNames;
import org.hibernate.metamodel.internal.source.annotations.util.JandexHelper;
import org.hibernate.metamodel.internal.source.annotations.xml.mocker.MockHelper;
import org.hibernate.metamodel.spi.source.MappingException;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.AnnotationValue;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.FieldInfo;
import org.jboss.jandex.Index;
import org.jboss.jandex.Type;
import org.jboss.logging.Logger;
/**
@ -87,6 +91,7 @@ public class AssociationAttribute extends MappedAttribute {
private AttributeTypeResolver resolver;
public static AssociationAttribute createAssociationAttribute(
ClassInfo classInfo,
String name,
Class<?> attributeType,
Nature attributeNature,
@ -94,6 +99,7 @@ public class AssociationAttribute extends MappedAttribute {
Map<DotName, List<AnnotationInstance>> annotations,
EntityBindingContext context) {
return new AssociationAttribute(
classInfo,
name,
attributeType,
attributeType,
@ -105,6 +111,7 @@ public class AssociationAttribute extends MappedAttribute {
}
AssociationAttribute(
ClassInfo classInfo,
String name,
Class<?> attributeType,
Class<?> referencedAttributeType,
@ -119,6 +126,23 @@ public class AssociationAttribute extends MappedAttribute {
annotations,
attributeNature.getAnnotationDotName()
);
if ( associationAnnotation == null &&
( attributeNature == Nature.ELEMENT_COLLECTION_BASIC || attributeNature == Nature.ELEMENT_COLLECTION_EMBEDDABLE ) ) {
AnnotationTarget target = MockHelper.getTarget(
context.getServiceRegistry(),
classInfo,
name,
MockHelper.TargetType.valueOf( accessType.toUpperCase() )
);
associationAnnotation = AnnotationInstance.create(
attributeNature.getAnnotationDotName(),
target,
MockHelper.EMPTY_ANNOTATION_VALUE_ARRAY
);
}
// using jandex we don't really care which exact type of annotation we are dealing with
this.referencedEntityType = determineReferencedEntityType( associationAnnotation, referencedAttributeType );

View File

@ -23,9 +23,13 @@
*/
package org.hibernate.metamodel.internal.source.annotations.attribute;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import javax.persistence.FetchType;
@ -77,17 +81,22 @@ public class PluralAssociationAttribute extends AssociationAttribute {
private final String explicitForeignKeyName;
private final PluralAttributeSource.Nature pluralAttributeNature;
private static final EnumSet<PluralAttributeSource.Nature> SHOULD_NOT_HAS_COLLECTION_ID = EnumSet.of( PluralAttributeSource.Nature.SET,
PluralAttributeSource.Nature.MAP, PluralAttributeSource.Nature.LIST, PluralAttributeSource.Nature.ARRAY );
private LazyCollectionOption lazyOption;
private final boolean isCollectionIdPresent;
public static PluralAssociationAttribute createPluralAssociationAttribute(ClassInfo entityClassInfo,
String name,
Class<?> attributeType,
Class<?> referencedAttributeType,
Nature attributeNature,
String accessType,
Map<DotName, List<AnnotationInstance>> annotations,
EntityBindingContext context) {
public static PluralAssociationAttribute createPluralAssociationAttribute(
ClassInfo entityClassInfo,
String name,
Class<?> attributeType,
Class<?> referencedAttributeType,
Nature attributeNature,
String accessType,
Map<DotName, List<AnnotationInstance>> annotations,
EntityBindingContext context) {
return new PluralAssociationAttribute(
entityClassInfo,
name,
@ -171,15 +180,16 @@ public class PluralAssociationAttribute extends AssociationAttribute {
return isIndexed;
}
private PluralAssociationAttribute(ClassInfo entityClassInfo,
String name,
Class<?> attributeType,
Class<?> referencedAttributeType,
Nature associationType,
String accessType,
Map<DotName, List<AnnotationInstance>> annotations,
EntityBindingContext context) {
super( name, attributeType, referencedAttributeType, associationType, accessType, annotations, context );
private PluralAssociationAttribute(
final ClassInfo entityClassInfo,
final String name,
final Class<?> attributeType,
final Class<?> referencedAttributeType,
final Nature associationType,
final String accessType,
final Map<DotName, List<AnnotationInstance>> annotations,
final EntityBindingContext context) {
super( entityClassInfo, name, attributeType, referencedAttributeType, associationType, accessType, annotations, context );
this.entityClassInfo = entityClassInfo;
this.whereClause = determineWereClause();
this.orderBy = determineOrderBy();
@ -215,7 +225,10 @@ public class PluralAssociationAttribute extends AssociationAttribute {
HibernateDotNames.SQL_DELETE_ALL, annotations()
);
this.onDeleteAction = determineOnDeleteAction();
this.isCollectionIdPresent = JandexHelper.getSingleAnnotation(
annotations,
HibernateDotNames.COLLECTION_ID
) != null;
final AnnotationInstance sortAnnotation = JandexHelper.getSingleAnnotation( annotations, HibernateDotNames.SORT );
if ( sortAnnotation == null ) {
this.sorted = false;
@ -249,15 +262,58 @@ public class PluralAssociationAttribute extends AssociationAttribute {
}
this.isIndexed = orderColumnAnnotation != null || indexColumnAnnotation != null;
this.pluralAttributeNature = resolvePluralAttributeNature();
validateMapping();
}
private void validateMapping() {
checkSortedTypeIsSortable();
checkIfCollectionIdIsWronglyPlaced();
}
private void checkIfCollectionIdIsWronglyPlaced() {
if ( isCollectionIdPresent && SHOULD_NOT_HAS_COLLECTION_ID.contains( pluralAttributeNature ) ) {
throw new MappingException(
"The Collection type doesn't support @CollectionId annotation: " + getRole(),
getContext().getOrigin()
);
}
}
private void checkSortedTypeIsSortable() {
//shortcut, a little performance improvement of avoiding the class type check
if ( pluralAttributeNature == PluralAttributeSource.Nature.MAP
|| pluralAttributeNature == PluralAttributeSource.Nature.SET ) {
if ( SortedMap.class.isAssignableFrom( getAttributeType() )
|| SortedSet.class.isAssignableFrom( getAttributeType() ) ) {
if ( !isSorted() ) {
throw new MappingException(
"A sorted collection has to define @Sort: " + getRole(),
getContext().getOrigin()
);
}
}
}
}
//TODO org.hibernate.cfg.annotations.CollectionBinder#hasToBeSorted
private PluralAttributeSource.Nature resolvePluralAttributeNature() {
if ( Map.class.isAssignableFrom( getAttributeType() ) ) {
return PluralAttributeSource.Nature.MAP;
}
else if ( List.class.isAssignableFrom( getAttributeType() ) ) {
return isIndexed() ? PluralAttributeSource.Nature.LIST : PluralAttributeSource.Nature.BAG;
if ( isIndexed() ) {
return PluralAttributeSource.Nature.LIST;
}
else if ( isCollectionIdPresent ) {
return PluralAttributeSource.Nature.ID_BAG;
}
else {
return PluralAttributeSource.Nature.BAG;
}
}
else if ( Set.class.isAssignableFrom( getAttributeType() ) ) {
return PluralAttributeSource.Nature.SET;
@ -265,22 +321,24 @@ public class PluralAssociationAttribute extends AssociationAttribute {
else if ( getAttributeType().isArray() ) {
return PluralAttributeSource.Nature.ARRAY;
}
else if ( Collection.class.isAssignableFrom( getAttributeType() ) ) {
return isCollectionIdPresent ? PluralAttributeSource.Nature.ID_BAG : PluralAttributeSource.Nature.BAG;
}
else {
return PluralAttributeSource.Nature.BAG;
}
}
private OnDeleteAction determineOnDeleteAction() {
OnDeleteAction action = null;
private OnDeleteAction determineOnDeleteAction() {
final AnnotationInstance onDeleteAnnotation = JandexHelper.getSingleAnnotation(
annotations(),
HibernateDotNames.ON_DELETE
);
if ( onDeleteAnnotation != null ) {
action = JandexHelper.getEnumValue( onDeleteAnnotation, "action", OnDeleteAction.class );
return JandexHelper.getEnumValue( onDeleteAnnotation, "action", OnDeleteAction.class );
}
return action;
return null;
}
@Override
@ -369,9 +427,10 @@ public class PluralAssociationAttribute extends AssociationAttribute {
);
if ( jpaWhereAnnotation != null && hibernateWhereAnnotation != null ) {
throw new AnnotationException(
throw new MappingException(
"Cannot use sql order by clause (@org.hibernate.annotations.OrderBy) " +
"in conjunction with JPA order by clause (@java.persistence.OrderBy) on " + getRole()
"in conjunction with JPA order by clause (@java.persistence.OrderBy) on " + getRole(),
getContext().getOrigin()
);
}
@ -385,12 +444,21 @@ public class PluralAssociationAttribute extends AssociationAttribute {
// associated entity is assumed
// The binder will need to take this into account and generate the right property names
orderBy = JandexHelper.getValue( jpaWhereAnnotation, "value", String.class );
orderBy = orderBy == null ? "" : orderBy;
if ( orderBy == null ) {
orderBy = isBasicCollection() ? "$element$ asc" :"id asc" ;
}
if ( orderBy.equalsIgnoreCase( "desc" ) ) {
orderBy = isBasicCollection() ? "$element$ desc" :"id desc";
}
}
return orderBy;
}
private boolean isBasicCollection(){
return getNature() == Nature.ELEMENT_COLLECTION_BASIC || getNature() == Nature.ELEMENT_COLLECTION_EMBEDDABLE;
}
private Caching determineCachingSettings() {
Caching caching = null;
final AnnotationInstance hibernateCacheAnnotation = JandexHelper.getSingleAnnotation(
@ -418,6 +486,8 @@ public class PluralAssociationAttribute extends AssociationAttribute {
}
return caching;
}
}

View File

@ -30,6 +30,7 @@ import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -46,6 +47,7 @@ import org.hibernate.HibernateException;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.internal.source.annotations.AnnotationBindingContext;
import org.hibernate.metamodel.internal.source.annotations.attribute.AssociationAttribute;
import org.hibernate.metamodel.internal.source.annotations.attribute.AttributeOverride;
@ -513,6 +515,7 @@ public class ConfiguredClass {
case ONE_TO_ONE:
case MANY_TO_ONE: {
final AssociationAttribute attribute = AssociationAttribute.createAssociationAttribute(
classInfo,
attributeName,
resolvedMember.getType().getErasedType(),
attributeNature,
@ -599,39 +602,36 @@ public class ConfiguredClass {
List<AnnotationInstance>> annotations,
Class<?> attributeType,
Class<?> referencedCollectionType ) {
EnumMap<MappedAttribute.Nature, AnnotationInstance> discoveredAttributeTypes =
new EnumMap<MappedAttribute.Nature, AnnotationInstance>( MappedAttribute.Nature.class );
EnumSet<MappedAttribute.Nature> discoveredAttributeTypes = EnumSet.noneOf( MappedAttribute.Nature.class );
AnnotationInstance oneToOne = JandexHelper.getSingleAnnotation( annotations, JPADotNames.ONE_TO_ONE );
if ( oneToOne != null ) {
discoveredAttributeTypes.put( MappedAttribute.Nature.ONE_TO_ONE, oneToOne );
discoveredAttributeTypes.add( MappedAttribute.Nature.ONE_TO_ONE );
}
AnnotationInstance oneToMany = JandexHelper.getSingleAnnotation( annotations, JPADotNames.ONE_TO_MANY );
if ( oneToMany != null ) {
discoveredAttributeTypes.put( MappedAttribute.Nature.ONE_TO_MANY, oneToMany );
discoveredAttributeTypes.add( MappedAttribute.Nature.ONE_TO_MANY );
}
AnnotationInstance manyToOne = JandexHelper.getSingleAnnotation( annotations, JPADotNames.MANY_TO_ONE );
if ( manyToOne != null ) {
discoveredAttributeTypes.put( MappedAttribute.Nature.MANY_TO_ONE, manyToOne );
discoveredAttributeTypes.add( MappedAttribute.Nature.MANY_TO_ONE );
}
AnnotationInstance manyToMany = JandexHelper.getSingleAnnotation( annotations, JPADotNames.MANY_TO_MANY );
if ( manyToMany != null ) {
discoveredAttributeTypes.put( MappedAttribute.Nature.MANY_TO_MANY, manyToMany );
discoveredAttributeTypes.add( MappedAttribute.Nature.MANY_TO_MANY );
}
AnnotationInstance embeddedId = JandexHelper.getSingleAnnotation( annotations, JPADotNames.EMBEDDED_ID );
if ( embeddedId != null ) {
discoveredAttributeTypes.put( MappedAttribute.Nature.EMBEDDED_ID, embeddedId );
discoveredAttributeTypes.add( MappedAttribute.Nature.EMBEDDED_ID );
}
AnnotationInstance embedded = JandexHelper.getSingleAnnotation(
annotations, JPADotNames.EMBEDDED );
if ( embedded != null ) {
discoveredAttributeTypes.put( MappedAttribute.Nature.EMBEDDED,
embedded );
discoveredAttributeTypes.add( MappedAttribute.Nature.EMBEDDED );
} else if ( embeddedId == null ) {
// For backward compatibility, we're allowing attributes of an
// @Embeddable type to leave off @Embedded. Check the type's
@ -644,8 +644,7 @@ public class ConfiguredClass {
&& JandexHelper.getSingleAnnotation(
typeClassInfo.annotations(),
JPADotNames.EMBEDDABLE ) != null ) {
discoveredAttributeTypes.put( MappedAttribute.Nature.EMBEDDED,
null );
discoveredAttributeTypes.add( MappedAttribute.Nature.EMBEDDED );
}
}
@ -653,19 +652,9 @@ public class ConfiguredClass {
annotations,
JPADotNames.ELEMENT_COLLECTION
);
if ( elementCollection != null ) {
// class info can be null for types like string, etc where there are no annotations
ClassInfo classInfo = getLocalBindingContext().getIndex().getClassByName(
DotName.createSimple(
referencedCollectionType.getName()
)
);
if ( classInfo != null && classInfo.annotations().get( JPADotNames.EMBEDDABLE ) != null ) {
discoveredAttributeTypes.put( MappedAttribute.Nature.ELEMENT_COLLECTION_EMBEDDABLE, elementCollection );
}
else {
discoveredAttributeTypes.put( MappedAttribute.Nature.ELEMENT_COLLECTION_BASIC, elementCollection );
}
if ( elementCollection != null || ( discoveredAttributeTypes.isEmpty() && CollectionHelper.isCollectionOrArray( attributeType ) )) {
boolean isEmbeddable = isEmbeddableType( referencedCollectionType );
discoveredAttributeTypes.add( isEmbeddable? MappedAttribute.Nature.ELEMENT_COLLECTION_EMBEDDABLE : MappedAttribute.Nature.ELEMENT_COLLECTION_BASIC );
}
int size = discoveredAttributeTypes.size();
@ -673,12 +662,22 @@ public class ConfiguredClass {
case 0:
return MappedAttribute.Nature.BASIC;
case 1:
return discoveredAttributeTypes.keySet().iterator().next();
return discoveredAttributeTypes.iterator().next();
default:
throw new AnnotationException( "More than one association type configured for property " + getName() + " of class " + getName() );
}
}
private boolean isEmbeddableType(Class<?> referencedCollectionType) {
// class info can be null for types like string, etc where there are no annotations
ClassInfo classInfo = getLocalBindingContext().getIndex().getClassByName(
DotName.createSimple(
referencedCollectionType.getName()
)
);
return classInfo != null && classInfo.annotations().get( JPADotNames.EMBEDDABLE ) != null;
}
private ResolvedMember findResolvedMember(String name, ResolvedMember[] resolvedMembers) {
for ( ResolvedMember resolvedMember : resolvedMembers ) {
if ( resolvedMember.getName().equals( name ) ) {

View File

@ -53,7 +53,7 @@ import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
*/
public class MockHelper {
static final AnnotationValue[] EMPTY_ANNOTATION_VALUE_ARRAY = new AnnotationValue[0];
public static final AnnotationValue[] EMPTY_ANNOTATION_VALUE_ARRAY = new AnnotationValue[0];
static final Type[] EMPTY_TYPE_ARRAY = new Type[0];
/**
@ -305,9 +305,9 @@ public class MockHelper {
);
}
enum TargetType {METHOD, FIELD, PROPERTY}
public enum TargetType {METHOD, FIELD, PROPERTY}
static AnnotationTarget getTarget(ServiceRegistry serviceRegistry, ClassInfo classInfo, String name, TargetType type) {
public static AnnotationTarget getTarget(ServiceRegistry serviceRegistry, ClassInfo classInfo, String name, TargetType type) {
Class clazz = serviceRegistry.getService( ClassLoaderService.class ).classForName( classInfo.toString() );
switch ( type ) {
case FIELD:
@ -440,7 +440,7 @@ public class MockHelper {
return Type.create( DotName.createSimple( clazz.getName() ), getTypeKind( clazz ) );
}
private static Type.Kind getTypeKind(Class clazz) {
public static Type.Kind getTypeKind(Class clazz) {
Type.Kind kind;
if ( clazz == Void.TYPE ) {
kind = Type.Kind.VOID;

View File

@ -51,7 +51,7 @@ public class BagAttributeSourceImpl extends AbstractPluralAttributeSourceImpl im
@Override
public boolean isOrdered() {
return getOrder() != null;
return StringHelper.isNotEmpty( getOrder() );
}
@Override

View File

@ -64,7 +64,7 @@ public class SetAttributeSourceImpl extends AbstractPluralAttributeSourceImpl im
@Override
public boolean isOrdered() {
return getOrder() != null;
return StringHelper.isNotEmpty( getOrder() );
}
@Override

View File

@ -26,6 +26,7 @@ package org.hibernate.test.annotations.collectionelement.indexedCollection;
import org.junit.Test;
import org.hibernate.Session;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals;
@ -33,6 +34,7 @@ import static org.junit.Assert.assertEquals;
/**
* @author Emmanuel Bernard
*/
@FailureExpectedWithNewMetamodel
public class IndexedCollectionOfElementsTest extends BaseCoreFunctionalTestCase {
@Test
public void testIndexedCollectionOfElements() throws Exception {