org.hibernate.query.criteria.internal.path.PluralAttributePath Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hibernate-core Show documentation
Show all versions of hibernate-core Show documentation
Hibernate's core ORM functionality
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or .
*/
package org.hibernate.query.criteria.internal.path;
import java.io.Serializable;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.Bindable;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.IdentifiableType;
import javax.persistence.metamodel.MappedSuperclassType;
import javax.persistence.metamodel.PluralAttribute;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.Type;
import org.hibernate.AssertionFailure;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.criteria.internal.CriteriaBuilderImpl;
import org.hibernate.query.criteria.internal.PathSource;
import org.hibernate.persister.collection.CollectionPersister;
/**
* Models a path for a {@link PluralAttribute} generally obtained from a
* {@link javax.persistence.criteria.Path#get} call
*
* @author Steve Ebersole
*/
public class PluralAttributePath extends AbstractPathImpl implements Serializable {
private final PluralAttribute attribute;
private final CollectionPersister persister;
public PluralAttributePath(
CriteriaBuilderImpl criteriaBuilder,
PathSource source,
PluralAttribute attribute) {
super( criteriaBuilder, attribute.getJavaType(), source );
this.attribute = attribute;
this.persister = resolvePersister( criteriaBuilder, attribute );
}
private CollectionPersister resolvePersister(CriteriaBuilderImpl criteriaBuilder, PluralAttribute attribute) {
SessionFactoryImplementor sfi = criteriaBuilder.getEntityManagerFactory().getSessionFactory();
return sfi.getCollectionPersister( resolveRole( attribute ) );
}
private String resolveRole(PluralAttribute attribute) {
switch ( attribute.getDeclaringType().getPersistenceType() ) {
case ENTITY: {
return attribute.getDeclaringType().getJavaType().getName() + '.' + attribute.getName();
}
case MAPPED_SUPERCLASS: {
// the attribute is declared in a mappedSuperclass
if ( getPathSource().getModel().getBindableType() == Bindable.BindableType.ENTITY_TYPE ) {
// the role will be assigned to the "nearest" EntityType subclass of the MappedSuperclassType
final EntityType entityTypeNearestDeclaringType = locateNearestSubclassEntity(
(MappedSuperclassType) attribute.getDeclaringType(),
(EntityType) getPathSource().getModel()
);
return entityTypeNearestDeclaringType.getJavaType().getName() + '.' + attribute.getName();
}
else {
throw new AssertionFailure(
String.format(
"Unexpected BindableType; expected [%s]; instead got [%s]",
Bindable.BindableType.ENTITY_TYPE,
getPathSource().getModel().getBindableType()
)
);
}
}
case EMBEDDABLE: {
// initialize role to '.' +
StringBuilder role = new StringBuilder().append( '.' ).append( attribute.getName() );
PathSource parentPath = getPathSource();
SingularAttribute singularAttribute;
do {
final SingularAttributePath singularAttributePath = (SingularAttributePath) parentPath;
singularAttribute = singularAttributePath.getAttribute();
// insert '.' + at start of role
role.insert( 0, '.' );
role.insert( 1, singularAttributePath.getAttribute().getName() );
parentPath = singularAttributePath.getPathSource();
} while ( ( SingularAttributePath.class.isInstance( parentPath ) ) );
final EntityType entityType;
if ( singularAttribute.getDeclaringType().getPersistenceType() == Type.PersistenceType.ENTITY ) {
entityType = (EntityType) singularAttribute.getDeclaringType();
}
else if ( singularAttribute.getDeclaringType().getPersistenceType() == Type.PersistenceType.MAPPED_SUPERCLASS ){
// find the "nearest" EntityType subclass of the MappedSuperclassType
entityType = locateNearestSubclassEntity(
(MappedSuperclassType) singularAttribute.getDeclaringType(),
(EntityType) parentPath.getModel()
);
}
else {
throw new AssertionFailure(
String.format(
"Unexpected PersistenceType: [%s]",
singularAttribute.getDeclaringType().getPersistenceType()
)
);
}
// insert at start of role
return role.insert( 0, entityType.getJavaType().getName() ).toString();
}
default:
throw new AssertionFailure(
String.format(
"Unexpected PersistenceType: [%s]",
attribute.getDeclaringType().getPersistenceType()
)
);
}
}
public PluralAttribute getAttribute() {
return attribute;
}
@SuppressWarnings({ "UnusedDeclaration" })
public CollectionPersister getPersister() {
return persister;
}
@Override
protected boolean canBeDereferenced() {
// cannot be dereferenced
return false;
}
@Override
protected Attribute locateAttributeInternal(String attributeName) {
throw new IllegalArgumentException( "Plural attribute paths cannot be further dereferenced" );
}
public Bindable getModel() {
// the issue here is the parameterized type; X is the collection
// type (Map, Set, etc) while the "bindable" for a collection is the
// elements.
//
// TODO : throw exception instead?
return null;
}
@Override
public PluralAttributePath treatAs(Class treatAsType) {
throw new UnsupportedOperationException(
"Plural attribute path [" + getPathSource().getPathIdentifier() + '.'
+ attribute.getName() + "] cannot be dereferenced"
);
}
private EntityType locateNearestSubclassEntity(MappedSuperclassType mappedSuperclassType, EntityType entityTypeTop) {
EntityType entityTypeNearestDeclaringType = entityTypeTop;
IdentifiableType superType = entityTypeNearestDeclaringType.getSupertype();
while ( superType != mappedSuperclassType ) {
if ( superType == null ) {
throw new IllegalStateException(
String.format(
"Cannot determine nearest EntityType extending mapped superclass [%s] starting from [%s]; a supertype of [%s] is null",
mappedSuperclassType.getJavaType().getName(),
entityTypeTop.getJavaType().getName(),
entityTypeTop.getJavaType().getName()
)
);
}
if ( superType.getPersistenceType() == Type.PersistenceType.ENTITY ) {
entityTypeNearestDeclaringType = (EntityType) superType;
}
superType = superType.getSupertype();
}
return entityTypeNearestDeclaringType;
}
}