mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-19 17:45:10 +00:00
6 - SQM based on JPA type system
- SQM tests
This commit is contained in:
parent
21f4cfb891
commit
1003ddf115
@ -12,6 +12,6 @@
|
||||
public enum ValueClassification {
|
||||
BASIC,
|
||||
ANY,
|
||||
EMBEDDED,
|
||||
EMBEDDABLE,
|
||||
ENTITY
|
||||
}
|
||||
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.internal;
|
||||
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.metamodel.model.domain.ManagedDomainType;
|
||||
|
||||
/**
|
||||
* Bundle's a Hibernate property mapping together with the JPA metamodel information
|
||||
* of the attribute owner.
|
||||
*
|
||||
* @param <X> The owner type.
|
||||
*/
|
||||
public interface AttributeContext<X> {
|
||||
/**
|
||||
* Retrieve the attribute owner.
|
||||
*
|
||||
* @return The owner.
|
||||
*/
|
||||
ManagedDomainType<X> getOwnerType();
|
||||
|
||||
/**
|
||||
* Retrieve the Hibernate property mapping.
|
||||
*
|
||||
* @return The Hibernate property mapping.
|
||||
*/
|
||||
Property getPropertyMapping();
|
||||
}
|
@ -10,13 +10,10 @@
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.lang.reflect.WildcardType;
|
||||
import java.util.Iterator;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.metamodel.Attribute;
|
||||
import javax.persistence.metamodel.PluralAttribute;
|
||||
import javax.persistence.metamodel.Type;
|
||||
|
||||
import org.hibernate.annotations.common.AssertionFailure;
|
||||
@ -38,7 +35,6 @@
|
||||
import org.hibernate.metamodel.model.domain.IdentifiableDomainType;
|
||||
import org.hibernate.metamodel.model.domain.ManagedDomainType;
|
||||
import org.hibernate.metamodel.model.domain.PersistentAttribute;
|
||||
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
|
||||
import org.hibernate.metamodel.model.domain.SimpleDomainType;
|
||||
import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
|
||||
import org.hibernate.metamodel.model.domain.internal.EmbeddableTypeImpl;
|
||||
@ -84,8 +80,15 @@ public AttributeFactory(MetadataContext context) {
|
||||
*
|
||||
* @return The built attribute descriptor or null if the attribute is not part of the JPA 2 model (eg backrefs)
|
||||
*/
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public <X, Y> PersistentAttribute<X, Y> buildAttribute(ManagedDomainType<X> ownerType, Property property) {
|
||||
return buildAttribute( ownerType, property, context );
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public static <X, Y> PersistentAttribute<X, Y> buildAttribute(
|
||||
ManagedDomainType<X> ownerType,
|
||||
Property property,
|
||||
MetadataContext metadataContext) {
|
||||
if ( property.isSynthetic() ) {
|
||||
// hide synthetic/virtual properties (fabricated by Hibernate) from the JPA metamodel.
|
||||
LOG.tracef( "Skipping synthetic property %s(%s)", ownerType.getTypeName(), property.getName() );
|
||||
@ -93,15 +96,19 @@ public <X, Y> PersistentAttribute<X, Y> buildAttribute(ManagedDomainType<X> owne
|
||||
}
|
||||
LOG.trace( "Building attribute [" + ownerType.getTypeName() + "." + property.getName() + "]" );
|
||||
final AttributeContext<X> attributeContext = wrap( ownerType, property );
|
||||
final AttributeMetadata<X, Y> attributeMetadata = determineAttributeMetadata( attributeContext, normalMemberResolver );
|
||||
final AttributeMetadata<X, Y> attributeMetadata = determineAttributeMetadata(
|
||||
attributeContext,
|
||||
normalMemberResolver,
|
||||
metadataContext
|
||||
);
|
||||
if ( attributeMetadata == null ) {
|
||||
return null;
|
||||
}
|
||||
if ( attributeMetadata.isPlural() ) {
|
||||
return buildPluralAttribute( (PluralAttributeMetadata) attributeMetadata );
|
||||
return PluralAttributeBuilder.build( (PluralAttributeMetadata) attributeMetadata, metadataContext );
|
||||
}
|
||||
final SingularAttributeMetadata<X, Y> singularAttributeMetadata = (SingularAttributeMetadata<X, Y>) attributeMetadata;
|
||||
final SimpleDomainType<Y> metaModelType = determineSimpleType( singularAttributeMetadata.getValueContext() );
|
||||
final SimpleDomainType<Y> metaModelType = determineSimpleType( singularAttributeMetadata.getValueContext(), metadataContext );
|
||||
return new SingularAttributeImpl(
|
||||
ownerType,
|
||||
attributeMetadata.getName(),
|
||||
@ -114,7 +121,7 @@ public <X, Y> PersistentAttribute<X, Y> buildAttribute(ManagedDomainType<X> owne
|
||||
);
|
||||
}
|
||||
|
||||
private <X> AttributeContext<X> wrap(final ManagedDomainType<X> ownerType, final Property property) {
|
||||
private static <X> AttributeContext<X> wrap(final ManagedDomainType<X> ownerType, final Property property) {
|
||||
return new AttributeContext<X>() {
|
||||
public ManagedDomainType<X> getOwnerType() {
|
||||
return ownerType;
|
||||
@ -186,42 +193,12 @@ public <X, Y> SingularAttributeImpl<X, Y> buildVersionAttribute(
|
||||
);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <X, Y, E, K> PluralPersistentAttribute<X,Y,E> buildPluralAttribute(PluralAttributeMetadata<X, Y, E> attributeMetadata) {
|
||||
final JavaTypeDescriptor<Y> javaTypeDescriptor = context
|
||||
.getTypeConfiguration()
|
||||
.getJavaTypeDescriptorRegistry()
|
||||
.getDescriptor( attributeMetadata.getJavaType() );
|
||||
|
||||
final PluralAttributeBuilder info = new PluralAttributeBuilder(
|
||||
attributeMetadata.getOwnerType(),
|
||||
determineSimpleType( attributeMetadata.getElementValueContext() ),
|
||||
javaTypeDescriptor,
|
||||
determineListIndexOrMapKeyType( attributeMetadata )
|
||||
);
|
||||
|
||||
return info
|
||||
.member( attributeMetadata.getMember() )
|
||||
.property( attributeMetadata.getPropertyMapping() )
|
||||
.persistentAttributeClassification( attributeMetadata.getAttributeClassification() )
|
||||
.build();
|
||||
}
|
||||
|
||||
private <X, Y, E> SimpleDomainType determineListIndexOrMapKeyType(PluralAttributeMetadata<X, Y, E> attributeMetadata) {
|
||||
if ( java.util.Map.class.isAssignableFrom( attributeMetadata.getJavaType() ) ) {
|
||||
return determineSimpleType( attributeMetadata.getMapKeyValueContext() );
|
||||
}
|
||||
|
||||
if ( java.util.List.class.isAssignableFrom( attributeMetadata.getJavaType() ) ) {
|
||||
|
||||
}
|
||||
return java.util.Map.class.isAssignableFrom( attributeMetadata.getJavaType() )
|
||||
? determineSimpleType( attributeMetadata.getMapKeyValueContext() )
|
||||
: null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <Y> SimpleDomainType<Y> determineSimpleType(ValueContext typeContext) {
|
||||
return determineSimpleType( typeContext, context );
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <Y> SimpleDomainType<Y> determineSimpleType(ValueContext typeContext, MetadataContext context) {
|
||||
switch ( typeContext.getValueClassification() ) {
|
||||
case BASIC: {
|
||||
return context.resolveBasicType( typeContext.getJpaBindableType() );
|
||||
@ -285,7 +262,7 @@ private <Y> SimpleDomainType<Y> determineSimpleType(ValueContext typeContext) {
|
||||
final Iterator<Property> subProperties = component.getPropertyIterator();
|
||||
while ( subProperties.hasNext() ) {
|
||||
final Property property = subProperties.next();
|
||||
final PersistentAttribute<Y, Object> attribute = buildAttribute( embeddableType, property );
|
||||
final PersistentAttribute<Y, Y> attribute = buildAttribute( embeddableType, property, context );
|
||||
if ( attribute != null ) {
|
||||
inFlightAccess.addAttribute( attribute );
|
||||
}
|
||||
@ -301,16 +278,22 @@ private <Y> SimpleDomainType<Y> determineSimpleType(ValueContext typeContext) {
|
||||
}
|
||||
|
||||
private EntityMetamodel getDeclarerEntityMetamodel(AbstractIdentifiableType<?> ownerType) {
|
||||
return getDeclarerEntityMetamodel( ownerType, context );
|
||||
}
|
||||
|
||||
private static EntityMetamodel getDeclarerEntityMetamodel(
|
||||
AbstractIdentifiableType<?> ownerType,
|
||||
MetadataContext metadataContext) {
|
||||
final Type.PersistenceType persistenceType = ownerType.getPersistenceType();
|
||||
if ( persistenceType == Type.PersistenceType.ENTITY ) {
|
||||
return context.getMetamodel()
|
||||
return metadataContext.getMetamodel()
|
||||
.getEntityDescriptor( ownerType.getTypeName() )
|
||||
.getEntityMetamodel();
|
||||
}
|
||||
else if ( persistenceType == Type.PersistenceType.MAPPED_SUPERCLASS ) {
|
||||
PersistentClass persistentClass =
|
||||
context.getPersistentClassHostingProperties( (MappedSuperclassTypeImpl<?>) ownerType );
|
||||
return context.getMetamodel()
|
||||
metadataContext.getPersistentClassHostingProperties( (MappedSuperclassTypeImpl<?>) ownerType );
|
||||
return metadataContext.getMetamodel()
|
||||
.findEntityDescriptor( persistentClass.getClassName() )
|
||||
.getEntityMetamodel();
|
||||
}
|
||||
@ -319,159 +302,6 @@ else if ( persistenceType == Type.PersistenceType.MAPPED_SUPERCLASS ) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A contract for defining the meta information about a {@link Value}
|
||||
*/
|
||||
private interface ValueContext {
|
||||
/**
|
||||
* Enum of the simplified types a value might be. These relate more to the Hibernate classification
|
||||
* then the JPA classification
|
||||
*/
|
||||
enum ValueClassification {
|
||||
EMBEDDABLE,
|
||||
ENTITY,
|
||||
BASIC
|
||||
}
|
||||
|
||||
ValueClassification getValueClassification();
|
||||
|
||||
Value getHibernateValue();
|
||||
|
||||
Class getJpaBindableType();
|
||||
|
||||
AttributeMetadata getAttributeMetadata();
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic contract for describing an attribute.
|
||||
*
|
||||
* @param <X> The attribute owner type
|
||||
* @param <Y> The attribute type.
|
||||
*/
|
||||
private interface AttributeMetadata<X, Y> {
|
||||
/**
|
||||
* Retrieve the name of the attribute
|
||||
*
|
||||
* @return The attribute name
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Retrieve the member defining the attribute
|
||||
*
|
||||
* @return The attribute member
|
||||
*/
|
||||
Member getMember();
|
||||
|
||||
/**
|
||||
* Retrieve the attribute java type.
|
||||
*
|
||||
* @return The java type of the attribute.
|
||||
*/
|
||||
Class<Y> getJavaType();
|
||||
|
||||
/**
|
||||
* Get the classification for this attribute
|
||||
*/
|
||||
AttributeClassification getAttributeClassification();
|
||||
|
||||
/**
|
||||
* Retrieve the attribute owner's metamodel information
|
||||
*
|
||||
* @return The metamodel information for the attribute owner
|
||||
*/
|
||||
ManagedDomainType<X> getOwnerType();
|
||||
|
||||
/**
|
||||
* Retrieve the Hibernate property mapping related to this attribute.
|
||||
*
|
||||
* @return The Hibernate property mapping
|
||||
*/
|
||||
Property getPropertyMapping();
|
||||
|
||||
/**
|
||||
* Is the attribute plural (a collection)?
|
||||
*
|
||||
* @return True if it is plural, false otherwise.
|
||||
*/
|
||||
boolean isPlural();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute metadata contract for a non-plural attribute.
|
||||
*
|
||||
* @param <X> The owner type
|
||||
* @param <Y> The attribute type
|
||||
*/
|
||||
private interface SingularAttributeMetadata<X, Y> extends AttributeMetadata<X, Y> {
|
||||
/**
|
||||
* Retrieve the value context for this attribute
|
||||
*
|
||||
* @return The attributes value context
|
||||
*/
|
||||
ValueContext getValueContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute metadata contract for a plural attribute.
|
||||
*
|
||||
* @param <X> The owner type
|
||||
* @param <Y> The attribute type (the collection type)
|
||||
* @param <E> The collection element type
|
||||
*/
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
private interface PluralAttributeMetadata<X, Y, E> extends AttributeMetadata<X, Y> {
|
||||
/**
|
||||
* Retrieve the JPA collection type classification for this attribute
|
||||
*
|
||||
* @return The JPA collection type classification
|
||||
*/
|
||||
PluralAttribute.CollectionType getAttributeCollectionType();
|
||||
|
||||
/**
|
||||
* Retrieve the value context for the collection's elements.
|
||||
*
|
||||
* @return The value context for the collection's elements.
|
||||
*/
|
||||
ValueContext getElementValueContext();
|
||||
|
||||
/**
|
||||
* Retrieve the value context for the collection's keys (if a map, null otherwise).
|
||||
*
|
||||
* @return The value context for the collection's keys (if a map, null otherwise).
|
||||
*/
|
||||
ValueContext getMapKeyValueContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Bundle's a Hibernate property mapping together with the JPA metamodel information
|
||||
* of the attribute owner.
|
||||
*
|
||||
* @param <X> The owner type.
|
||||
*/
|
||||
private interface AttributeContext<X> {
|
||||
/**
|
||||
* Retrieve the attribute owner.
|
||||
*
|
||||
* @return The owner.
|
||||
*/
|
||||
ManagedDomainType<X> getOwnerType();
|
||||
|
||||
/**
|
||||
* Retrieve the Hibernate property mapping.
|
||||
*
|
||||
* @return The Hibernate property mapping.
|
||||
*/
|
||||
Property getPropertyMapping();
|
||||
}
|
||||
|
||||
/**
|
||||
* Contract for how we resolve the {@link Member} for a give attribute context.
|
||||
*/
|
||||
private interface MemberResolver {
|
||||
Member resolveMember(AttributeContext attributeContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Here is most of the nuts and bolts of this factory, where we interpret the known JPA metadata
|
||||
* against the known Hibernate metadata and build a descriptor for the attribute.
|
||||
@ -487,12 +317,19 @@ private interface MemberResolver {
|
||||
private <X, Y> AttributeMetadata<X, Y> determineAttributeMetadata(
|
||||
AttributeContext<X> attributeContext,
|
||||
MemberResolver memberResolver) {
|
||||
return determineAttributeMetadata( attributeContext, memberResolver, context );
|
||||
}
|
||||
|
||||
private static <X, Y> AttributeMetadata<X, Y> determineAttributeMetadata(
|
||||
AttributeContext<X> attributeContext,
|
||||
MemberResolver memberResolver,
|
||||
MetadataContext context) {
|
||||
final Property propertyMapping = attributeContext.getPropertyMapping();
|
||||
final String propertyName = propertyMapping.getName();
|
||||
|
||||
LOG.trace( "Starting attribute metadata determination [" + propertyName + "]" );
|
||||
|
||||
final Member member = memberResolver.resolveMember( attributeContext );
|
||||
final Member member = memberResolver.resolveMember( attributeContext, context );
|
||||
LOG.trace( " Determined member [" + member + "]" );
|
||||
|
||||
final Value value = propertyMapping.getValue();
|
||||
@ -504,7 +341,8 @@ private <X, Y> AttributeMetadata<X, Y> determineAttributeMetadata(
|
||||
propertyMapping,
|
||||
attributeContext.getOwnerType(),
|
||||
member,
|
||||
AttributeClassification.ANY
|
||||
AttributeClassification.ANY,
|
||||
context
|
||||
);
|
||||
}
|
||||
else if ( type.isAssociationType() ) {
|
||||
@ -515,7 +353,8 @@ else if ( type.isAssociationType() ) {
|
||||
propertyMapping,
|
||||
attributeContext.getOwnerType(),
|
||||
member,
|
||||
determineSingularAssociationClassification( member )
|
||||
determineSingularAssociationClassification( member ),
|
||||
context
|
||||
);
|
||||
}
|
||||
// collection
|
||||
@ -580,7 +419,8 @@ else if ( value instanceof List ) {
|
||||
member,
|
||||
attributeClassification,
|
||||
elementClassification,
|
||||
indexClassification
|
||||
indexClassification,
|
||||
context
|
||||
);
|
||||
}
|
||||
else if ( value instanceof OneToMany ) {
|
||||
@ -609,7 +449,8 @@ else if ( propertyMapping.isComposite() ) {
|
||||
propertyMapping,
|
||||
attributeContext.getOwnerType(),
|
||||
member,
|
||||
AttributeClassification.EMBEDDED
|
||||
AttributeClassification.EMBEDDED,
|
||||
context
|
||||
);
|
||||
}
|
||||
else {
|
||||
@ -618,7 +459,8 @@ else if ( propertyMapping.isComposite() ) {
|
||||
propertyMapping,
|
||||
attributeContext.getOwnerType(),
|
||||
member,
|
||||
AttributeClassification.BASIC
|
||||
AttributeClassification.BASIC,
|
||||
context
|
||||
);
|
||||
}
|
||||
throw new UnsupportedOperationException( "oops, we are missing something: " + propertyMapping );
|
||||
@ -640,85 +482,11 @@ else if ( member instanceof MapMember ) {
|
||||
}
|
||||
}
|
||||
|
||||
private abstract class BaseAttributeMetadata<X, Y> implements AttributeMetadata<X, Y> {
|
||||
private final Property propertyMapping;
|
||||
private final ManagedDomainType<X> ownerType;
|
||||
private final Member member;
|
||||
private final Class<Y> javaType;
|
||||
private final AttributeClassification attributeClassification;
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
protected BaseAttributeMetadata(
|
||||
Property propertyMapping,
|
||||
ManagedDomainType<X> ownerType,
|
||||
Member member,
|
||||
AttributeClassification attributeClassification) {
|
||||
this.propertyMapping = propertyMapping;
|
||||
this.ownerType = ownerType;
|
||||
this.member = member;
|
||||
this.attributeClassification = attributeClassification;
|
||||
|
||||
final Class declaredType;
|
||||
|
||||
if ( member == null ) {
|
||||
// assume we have a MAP entity-mode "class"
|
||||
declaredType = propertyMapping.getType().getReturnedClass();
|
||||
}
|
||||
else if ( Field.class.isInstance( member ) ) {
|
||||
declaredType = ( (Field) member ).getType();
|
||||
}
|
||||
else if ( Method.class.isInstance( member ) ) {
|
||||
declaredType = ( (Method) member ).getReturnType();
|
||||
}
|
||||
else if ( MapMember.class.isInstance( member ) ) {
|
||||
declaredType = ( (MapMember) member ).getType();
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException( "Cannot determine java-type from given member [" + member + "]" );
|
||||
}
|
||||
this.javaType = accountForPrimitiveTypes( declaredType );
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return propertyMapping.getName();
|
||||
}
|
||||
|
||||
public Member getMember() {
|
||||
return member;
|
||||
}
|
||||
|
||||
public String getMemberDescription() {
|
||||
return determineMemberDescription( getMember() );
|
||||
}
|
||||
|
||||
public String determineMemberDescription(Member member) {
|
||||
return member.getDeclaringClass().getName() + '#' + member.getName();
|
||||
}
|
||||
|
||||
public Class<Y> getJavaType() {
|
||||
return javaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeClassification getAttributeClassification() {
|
||||
return attributeClassification;
|
||||
}
|
||||
|
||||
public ManagedDomainType<X> getOwnerType() {
|
||||
return ownerType;
|
||||
}
|
||||
|
||||
public boolean isPlural() {
|
||||
return propertyMapping.getType().isCollectionType();
|
||||
}
|
||||
|
||||
public Property getPropertyMapping() {
|
||||
return propertyMapping;
|
||||
}
|
||||
protected <Y> Class<Y> accountForPrimitiveTypes(Class<Y> declaredType) {
|
||||
return accountForPrimitiveTypes( declaredType, context );
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
protected <Y> Class<Y> accountForPrimitiveTypes(Class<Y> declaredType) {
|
||||
public static <Y> Class<Y> accountForPrimitiveTypes(Class<Y> declaredType, MetadataContext metadataContext) {
|
||||
// if ( !declaredType.isPrimitive() ) {
|
||||
// return declaredType;
|
||||
// }
|
||||
@ -753,196 +521,12 @@ protected <Y> Class<Y> accountForPrimitiveTypes(Class<Y> declaredType) {
|
||||
return declaredType;
|
||||
}
|
||||
|
||||
private class SingularAttributeMetadataImpl<X, Y>
|
||||
extends BaseAttributeMetadata<X, Y>
|
||||
implements SingularAttributeMetadata<X, Y> {
|
||||
private final ValueContext valueContext;
|
||||
|
||||
private SingularAttributeMetadataImpl(
|
||||
Property propertyMapping,
|
||||
ManagedDomainType<X> ownerType,
|
||||
Member member,
|
||||
AttributeClassification attributeClassification) {
|
||||
super( propertyMapping, ownerType, member, attributeClassification );
|
||||
valueContext = new ValueContext() {
|
||||
public Value getHibernateValue() {
|
||||
return getPropertyMapping().getValue();
|
||||
}
|
||||
|
||||
public Class getJpaBindableType() {
|
||||
return getAttributeMetadata().getJavaType();
|
||||
}
|
||||
|
||||
public ValueClassification getValueClassification() {
|
||||
switch ( attributeClassification ) {
|
||||
case EMBEDDED: {
|
||||
return ValueClassification.EMBEDDABLE;
|
||||
}
|
||||
case BASIC: {
|
||||
return ValueClassification.BASIC;
|
||||
}
|
||||
default: {
|
||||
return ValueClassification.ENTITY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AttributeMetadata getAttributeMetadata() {
|
||||
return SingularAttributeMetadataImpl.this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public ValueContext getValueContext() {
|
||||
return valueContext;
|
||||
}
|
||||
}
|
||||
|
||||
private class PluralAttributeMetadataImpl<X, Y, E>
|
||||
extends BaseAttributeMetadata<X, Y>
|
||||
implements PluralAttributeMetadata<X, Y, E> {
|
||||
private final PluralAttribute.CollectionType attributeCollectionType;
|
||||
private final AttributeClassification elementClassification;
|
||||
private final AttributeClassification listIndexOrMapKeyClassification;
|
||||
private final Class elementJavaType;
|
||||
private final Class keyJavaType;
|
||||
private final ValueContext elementValueContext;
|
||||
private final ValueContext keyValueContext;
|
||||
|
||||
private PluralAttributeMetadataImpl(
|
||||
Property propertyMapping,
|
||||
ManagedDomainType<X> ownerType,
|
||||
Member member,
|
||||
AttributeClassification attributeClassification,
|
||||
AttributeClassification elementClassification,
|
||||
AttributeClassification listIndexOrMapKeyClassification) {
|
||||
super( propertyMapping, ownerType, member, attributeClassification );
|
||||
this.attributeCollectionType = determineCollectionType( getJavaType() );
|
||||
this.elementClassification = elementClassification;
|
||||
this.listIndexOrMapKeyClassification = listIndexOrMapKeyClassification;
|
||||
|
||||
ParameterizedType signatureType = getSignatureType( member );
|
||||
if ( this.listIndexOrMapKeyClassification == null ) {
|
||||
elementJavaType = signatureType != null ?
|
||||
getClassFromGenericArgument( signatureType.getActualTypeArguments()[0] ) :
|
||||
Object.class; //FIXME and honor targetEntity?
|
||||
keyJavaType = null;
|
||||
}
|
||||
else {
|
||||
keyJavaType = signatureType != null ?
|
||||
getClassFromGenericArgument( signatureType.getActualTypeArguments()[0] ) :
|
||||
Object.class; //FIXME and honor targetEntity?
|
||||
elementJavaType = signatureType != null ?
|
||||
getClassFromGenericArgument( signatureType.getActualTypeArguments()[1] ) :
|
||||
Object.class; //FIXME and honor targetEntity?
|
||||
}
|
||||
|
||||
this.elementValueContext = new ValueContext() {
|
||||
public Value getHibernateValue() {
|
||||
return ( (Collection) getPropertyMapping().getValue() ).getElement();
|
||||
}
|
||||
|
||||
public Class getJpaBindableType() {
|
||||
return elementJavaType;
|
||||
}
|
||||
|
||||
public ValueClassification getValueClassification() {
|
||||
switch ( PluralAttributeMetadataImpl.this.elementClassification ) {
|
||||
case EMBEDDED: {
|
||||
return ValueClassification.EMBEDDABLE;
|
||||
}
|
||||
case BASIC: {
|
||||
return ValueClassification.BASIC;
|
||||
}
|
||||
default: {
|
||||
return ValueClassification.ENTITY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AttributeMetadata getAttributeMetadata() {
|
||||
return PluralAttributeMetadataImpl.this;
|
||||
}
|
||||
};
|
||||
|
||||
// interpret the key, if one
|
||||
if ( this.listIndexOrMapKeyClassification != null ) {
|
||||
this.keyValueContext = new ValueContext() {
|
||||
public Value getHibernateValue() {
|
||||
return ( (Map) getPropertyMapping().getValue() ).getIndex();
|
||||
}
|
||||
|
||||
public Class getJpaBindableType() {
|
||||
return keyJavaType;
|
||||
}
|
||||
|
||||
public ValueClassification getValueClassification() {
|
||||
switch ( PluralAttributeMetadataImpl.this.listIndexOrMapKeyClassification ) {
|
||||
case EMBEDDED: {
|
||||
return ValueClassification.EMBEDDABLE;
|
||||
}
|
||||
case BASIC: {
|
||||
return ValueClassification.BASIC;
|
||||
}
|
||||
default: {
|
||||
return ValueClassification.ENTITY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AttributeMetadata getAttributeMetadata() {
|
||||
return PluralAttributeMetadataImpl.this;
|
||||
}
|
||||
};
|
||||
}
|
||||
else {
|
||||
keyValueContext = null;
|
||||
}
|
||||
}
|
||||
|
||||
private Class<?> getClassFromGenericArgument(java.lang.reflect.Type type) {
|
||||
if ( type instanceof Class ) {
|
||||
return (Class) type;
|
||||
}
|
||||
else if ( type instanceof TypeVariable ) {
|
||||
final java.lang.reflect.Type upperBound = ( (TypeVariable) type ).getBounds()[0];
|
||||
return getClassFromGenericArgument( upperBound );
|
||||
}
|
||||
else if ( type instanceof ParameterizedType ) {
|
||||
final java.lang.reflect.Type rawType = ( (ParameterizedType) type ).getRawType();
|
||||
return getClassFromGenericArgument( rawType );
|
||||
}
|
||||
else if ( type instanceof WildcardType ) {
|
||||
final java.lang.reflect.Type upperBound = ( (WildcardType) type ).getUpperBounds()[0];
|
||||
return getClassFromGenericArgument( upperBound );
|
||||
}
|
||||
else {
|
||||
throw new AssertionFailure(
|
||||
"Fail to process type argument in a generic declaration. Member : " + getMemberDescription()
|
||||
+ " Type: " + type.getClass()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public ValueContext getElementValueContext() {
|
||||
return elementValueContext;
|
||||
}
|
||||
|
||||
public PluralAttribute.CollectionType getAttributeCollectionType() {
|
||||
return attributeCollectionType;
|
||||
}
|
||||
|
||||
public ValueContext getMapKeyValueContext() {
|
||||
return keyValueContext;
|
||||
}
|
||||
}
|
||||
|
||||
public static ParameterizedType getSignatureType(Member member) {
|
||||
final java.lang.reflect.Type type;
|
||||
if ( Field.class.isInstance( member ) ) {
|
||||
if ( member instanceof Field ) {
|
||||
type = ( (Field) member ).getGenericType();
|
||||
}
|
||||
else if ( Method.class.isInstance( member ) ) {
|
||||
else if ( member instanceof Method ) {
|
||||
type = ( (Method) member ).getGenericReturnType();
|
||||
}
|
||||
else {
|
||||
@ -955,39 +539,18 @@ else if ( Method.class.isInstance( member ) ) {
|
||||
return (ParameterizedType) type;
|
||||
}
|
||||
|
||||
public static PluralAttribute.CollectionType determineCollectionType(Class javaType) {
|
||||
if ( java.util.List.class.isAssignableFrom( javaType ) ) {
|
||||
return PluralAttribute.CollectionType.LIST;
|
||||
}
|
||||
else if ( java.util.Set.class.isAssignableFrom( javaType ) ) {
|
||||
return PluralAttribute.CollectionType.SET;
|
||||
}
|
||||
else if ( java.util.Map.class.isAssignableFrom( javaType ) ) {
|
||||
return PluralAttribute.CollectionType.MAP;
|
||||
}
|
||||
else if ( java.util.Collection.class.isAssignableFrom( javaType ) ) {
|
||||
return PluralAttribute.CollectionType.COLLECTION;
|
||||
}
|
||||
else if ( javaType.isArray() ) {
|
||||
return PluralAttribute.CollectionType.LIST;
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException( "Expecting collection type [" + javaType.getName() + "]" );
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isManyToMany(Member member) {
|
||||
if ( Field.class.isInstance( member ) ) {
|
||||
if ( member instanceof Field ) {
|
||||
return ( (Field) member ).getAnnotation( ManyToMany.class ) != null;
|
||||
}
|
||||
else if ( Method.class.isInstance( member ) ) {
|
||||
else if ( member instanceof Method ) {
|
||||
return ( (Method) member ).getAnnotation( ManyToMany.class ) != null;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private final MemberResolver embeddedMemberResolver = attributeContext -> {
|
||||
private static final MemberResolver embeddedMemberResolver = (attributeContext, metadataContext) -> {
|
||||
// the owner is an embeddable
|
||||
final EmbeddableDomainType<?> ownerType = (EmbeddableDomainType) attributeContext.getOwnerType();
|
||||
|
||||
@ -1003,9 +566,9 @@ else if ( Method.class.isInstance( member ) ) {
|
||||
};
|
||||
|
||||
|
||||
private final MemberResolver virtualIdentifierMemberResolver = attributeContext -> {
|
||||
private static final MemberResolver virtualIdentifierMemberResolver = (attributeContext, metadataContext) -> {
|
||||
final AbstractIdentifiableType identifiableType = (AbstractIdentifiableType) attributeContext.getOwnerType();
|
||||
final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( identifiableType );
|
||||
final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( identifiableType, metadataContext );
|
||||
if ( !entityMetamodel.getIdentifierProperty().isVirtual() ) {
|
||||
throw new IllegalArgumentException( "expecting IdClass mapping" );
|
||||
}
|
||||
@ -1028,22 +591,22 @@ else if ( Method.class.isInstance( member ) ) {
|
||||
/**
|
||||
* A {@link Member} resolver for normal attributes.
|
||||
*/
|
||||
private final MemberResolver normalMemberResolver = attributeContext -> {
|
||||
private static final MemberResolver normalMemberResolver = (attributeContext, metadataContext) -> {
|
||||
final ManagedDomainType ownerType = attributeContext.getOwnerType();
|
||||
final Property property = attributeContext.getPropertyMapping();
|
||||
final Type.PersistenceType persistenceType = ownerType.getPersistenceType();
|
||||
if ( Type.PersistenceType.EMBEDDABLE == persistenceType ) {
|
||||
return embeddedMemberResolver.resolveMember( attributeContext );
|
||||
return embeddedMemberResolver.resolveMember( attributeContext, metadataContext );
|
||||
}
|
||||
else if ( Type.PersistenceType.ENTITY == persistenceType
|
||||
|| Type.PersistenceType.MAPPED_SUPERCLASS == persistenceType ) {
|
||||
final AbstractIdentifiableType identifiableType = (AbstractIdentifiableType) ownerType;
|
||||
final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( identifiableType );
|
||||
final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( identifiableType, metadataContext );
|
||||
final String propertyName = property.getName();
|
||||
final Integer index = entityMetamodel.getPropertyIndexOrNull( propertyName );
|
||||
if ( index == null ) {
|
||||
// just like in #determineIdentifierJavaMember , this *should* indicate we have an IdClass mapping
|
||||
return virtualIdentifierMemberResolver.resolveMember( attributeContext );
|
||||
return virtualIdentifierMemberResolver.resolveMember( attributeContext, metadataContext );
|
||||
}
|
||||
else {
|
||||
final Getter getter = entityMetamodel.getTuplizer().getGetter( index );
|
||||
@ -1057,13 +620,13 @@ else if ( Type.PersistenceType.ENTITY == persistenceType
|
||||
}
|
||||
};
|
||||
|
||||
private final MemberResolver identifierMemberResolver = attributeContext -> {
|
||||
private final MemberResolver identifierMemberResolver = (attributeContext, metadataContext) -> {
|
||||
final AbstractIdentifiableType identifiableType = (AbstractIdentifiableType) attributeContext.getOwnerType();
|
||||
final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( identifiableType );
|
||||
if ( !attributeContext.getPropertyMapping().getName()
|
||||
.equals( entityMetamodel.getIdentifierProperty().getName() ) ) {
|
||||
// this *should* indicate processing part of an IdClass...
|
||||
return virtualIdentifierMemberResolver.resolveMember( attributeContext );
|
||||
return virtualIdentifierMemberResolver.resolveMember( attributeContext, metadataContext );
|
||||
}
|
||||
final Getter getter = entityMetamodel.getTuplizer().getIdentifierGetter();
|
||||
if ( PropertyAccessMapImpl.GetterImpl.class.isInstance( getter ) ) {
|
||||
@ -1079,7 +642,9 @@ else if ( Type.PersistenceType.ENTITY == persistenceType
|
||||
|
||||
private final MemberResolver versionMemberResolver = new MemberResolver() {
|
||||
@Override
|
||||
public Member resolveMember(AttributeContext attributeContext) {
|
||||
public Member resolveMember(
|
||||
AttributeContext attributeContext,
|
||||
MetadataContext metadataContext) {
|
||||
final AbstractIdentifiableType identifiableType = (AbstractIdentifiableType) attributeContext.getOwnerType();
|
||||
final EntityMetamodel entityMetamodel = getDeclarerEntityMetamodel( identifiableType );
|
||||
final String versionPropertyName = attributeContext.getPropertyMapping().getName();
|
||||
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.internal;
|
||||
|
||||
import java.lang.reflect.Member;
|
||||
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.metamodel.AttributeClassification;
|
||||
import org.hibernate.metamodel.CollectionClassification;
|
||||
import org.hibernate.metamodel.model.domain.ManagedDomainType;
|
||||
|
||||
/**
|
||||
* Basic contract for describing an attribute.
|
||||
*
|
||||
* @param <X> The attribute owner type
|
||||
* @param <Y> The attribute type.
|
||||
*/
|
||||
public interface AttributeMetadata<X, Y> {
|
||||
/**
|
||||
* Retrieve the name of the attribute
|
||||
*
|
||||
* @return The attribute name
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Retrieve the member defining the attribute
|
||||
*
|
||||
* @return The attribute member
|
||||
*/
|
||||
Member getMember();
|
||||
|
||||
/**
|
||||
* Retrieve the attribute java type.
|
||||
*
|
||||
* @return The java type of the attribute.
|
||||
*/
|
||||
Class<Y> getJavaType();
|
||||
|
||||
/**
|
||||
* Get the classification for this attribute
|
||||
*/
|
||||
AttributeClassification getAttributeClassification();
|
||||
|
||||
/**
|
||||
* Retrieve the attribute owner's metamodel information
|
||||
*
|
||||
* @return The metamodel information for the attribute owner
|
||||
*/
|
||||
ManagedDomainType<X> getOwnerType();
|
||||
|
||||
/**
|
||||
* Retrieve the Hibernate property mapping related to this attribute.
|
||||
*
|
||||
* @return The Hibernate property mapping
|
||||
*/
|
||||
Property getPropertyMapping();
|
||||
|
||||
/**
|
||||
* Is the attribute plural (a collection)?
|
||||
*
|
||||
* @return True if it is plural, false otherwise.
|
||||
*/
|
||||
boolean isPlural();
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.internal;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.metamodel.AttributeClassification;
|
||||
import org.hibernate.metamodel.model.domain.ManagedDomainType;
|
||||
import org.hibernate.metamodel.model.domain.internal.MapMember;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class BaseAttributeMetadata<X, Y> implements AttributeMetadata<X, Y> {
|
||||
private final Property propertyMapping;
|
||||
private final ManagedDomainType<X> ownerType;
|
||||
private final Member member;
|
||||
private final Class<Y> javaType;
|
||||
private final AttributeClassification attributeClassification;
|
||||
|
||||
protected BaseAttributeMetadata(
|
||||
Property propertyMapping,
|
||||
ManagedDomainType<X> ownerType,
|
||||
Member member,
|
||||
AttributeClassification attributeClassification,
|
||||
MetadataContext metadataContext) {
|
||||
this.propertyMapping = propertyMapping;
|
||||
this.ownerType = ownerType;
|
||||
this.member = member;
|
||||
this.attributeClassification = attributeClassification;
|
||||
|
||||
final Class declaredType;
|
||||
|
||||
if ( member == null ) {
|
||||
// assume we have a MAP entity-mode "class"
|
||||
declaredType = propertyMapping.getType().getReturnedClass();
|
||||
}
|
||||
else if ( member instanceof Field ) {
|
||||
declaredType = ( (Field) member ).getType();
|
||||
}
|
||||
else if ( member instanceof Method ) {
|
||||
declaredType = ( (Method) member ).getReturnType();
|
||||
}
|
||||
else if ( member instanceof MapMember ) {
|
||||
declaredType = ( (MapMember) member ).getType();
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException( "Cannot determine java-type from given member [" + member + "]" );
|
||||
}
|
||||
//noinspection unchecked
|
||||
this.javaType = AttributeFactory.accountForPrimitiveTypes( declaredType, metadataContext );
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return propertyMapping.getName();
|
||||
}
|
||||
|
||||
public Member getMember() {
|
||||
return member;
|
||||
}
|
||||
|
||||
public String getMemberDescription() {
|
||||
return determineMemberDescription( getMember() );
|
||||
}
|
||||
|
||||
public String determineMemberDescription(Member member) {
|
||||
return member.getDeclaringClass().getName() + '#' + member.getName();
|
||||
}
|
||||
|
||||
public Class<Y> getJavaType() {
|
||||
return javaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeClassification getAttributeClassification() {
|
||||
return attributeClassification;
|
||||
}
|
||||
|
||||
public ManagedDomainType<X> getOwnerType() {
|
||||
return ownerType;
|
||||
}
|
||||
|
||||
public boolean isPlural() {
|
||||
return propertyMapping.getType().isCollectionType();
|
||||
}
|
||||
|
||||
public Property getPropertyMapping() {
|
||||
return propertyMapping;
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.internal;
|
||||
|
||||
import java.lang.reflect.Member;
|
||||
|
||||
/**
|
||||
* Contract for how we resolve the {@link Member} for a give attribute context.
|
||||
*/
|
||||
public interface MemberResolver {
|
||||
Member resolveMember(AttributeContext attributeContext, MetadataContext metadataContext);
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.internal;
|
||||
|
||||
import javax.persistence.metamodel.PluralAttribute;
|
||||
|
||||
import org.hibernate.metamodel.CollectionClassification;
|
||||
|
||||
/**
|
||||
* Attribute metadata contract for a plural attribute.
|
||||
*
|
||||
* @param <X> The owner type
|
||||
* @param <Y> The attribute type (the collection type)
|
||||
* @param <E> The collection element type
|
||||
*/
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public interface PluralAttributeMetadata<X, Y, E> extends AttributeMetadata<X, Y> {
|
||||
/**
|
||||
* The classification of the collection, indicating the collection semantics
|
||||
* to be used.
|
||||
*/
|
||||
CollectionClassification getCollectionClassification();
|
||||
|
||||
/**
|
||||
* Retrieve the value context for the collection's elements.
|
||||
*
|
||||
* @return The value context for the collection's elements.
|
||||
*/
|
||||
ValueContext getElementValueContext();
|
||||
|
||||
/**
|
||||
* Retrieve the value context for the collection's keys (if a map, null otherwise).
|
||||
*
|
||||
* @return The value context for the collection's keys (if a map, null otherwise).
|
||||
*/
|
||||
ValueContext getMapKeyValueContext();
|
||||
}
|
@ -0,0 +1,226 @@
|
||||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.internal;
|
||||
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.lang.reflect.WildcardType;
|
||||
|
||||
import org.hibernate.annotations.common.AssertionFailure;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.Map;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.metamodel.AttributeClassification;
|
||||
import org.hibernate.metamodel.CollectionClassification;
|
||||
import org.hibernate.metamodel.ValueClassification;
|
||||
import org.hibernate.metamodel.model.domain.ManagedDomainType;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
class PluralAttributeMetadataImpl<X, Y, E>
|
||||
extends BaseAttributeMetadata<X, Y>
|
||||
implements PluralAttributeMetadata<X, Y, E> {
|
||||
private final CollectionClassification collectionClassification;
|
||||
private final AttributeClassification elementClassification;
|
||||
private final AttributeClassification listIndexOrMapKeyClassification;
|
||||
private final Class elementJavaType;
|
||||
private final Class keyJavaType;
|
||||
private final ValueContext elementValueContext;
|
||||
private final ValueContext keyValueContext;
|
||||
|
||||
PluralAttributeMetadataImpl(
|
||||
Property propertyMapping,
|
||||
ManagedDomainType<X> ownerType,
|
||||
Member member,
|
||||
AttributeClassification attributeClassification,
|
||||
AttributeClassification elementClassification,
|
||||
AttributeClassification listIndexOrMapKeyClassification,
|
||||
MetadataContext metadataContext) {
|
||||
super( propertyMapping, ownerType, member, attributeClassification, metadataContext );
|
||||
this.collectionClassification = determineCollectionType( getJavaType(), propertyMapping );
|
||||
this.elementClassification = elementClassification;
|
||||
this.listIndexOrMapKeyClassification = listIndexOrMapKeyClassification;
|
||||
|
||||
final ParameterizedType signatureType = AttributeFactory.getSignatureType( member );
|
||||
switch ( collectionClassification ) {
|
||||
case MAP:
|
||||
case SORTED_MAP:
|
||||
case ORDERED_MAP: {
|
||||
this.keyJavaType = signatureType != null
|
||||
? getClassFromGenericArgument( signatureType.getActualTypeArguments()[0] )
|
||||
: Object.class;
|
||||
|
||||
this.elementJavaType = signatureType != null
|
||||
? getClassFromGenericArgument( signatureType.getActualTypeArguments()[1] )
|
||||
: Object.class;
|
||||
|
||||
break;
|
||||
}
|
||||
case ARRAY:
|
||||
case LIST: {
|
||||
this.keyJavaType = Integer.class;
|
||||
|
||||
this.elementJavaType = signatureType != null
|
||||
? getClassFromGenericArgument( signatureType.getActualTypeArguments()[0] )
|
||||
: Object.class;
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
this.elementJavaType = signatureType != null
|
||||
? getClassFromGenericArgument( signatureType.getActualTypeArguments()[0] )
|
||||
: Object.class;
|
||||
this.keyJavaType = null;
|
||||
}
|
||||
}
|
||||
|
||||
this.elementValueContext = new ValueContext() {
|
||||
public Value getHibernateValue() {
|
||||
return ( (Collection) getPropertyMapping().getValue() ).getElement();
|
||||
}
|
||||
|
||||
public Class getJpaBindableType() {
|
||||
return elementJavaType;
|
||||
}
|
||||
|
||||
public ValueClassification getValueClassification() {
|
||||
switch ( PluralAttributeMetadataImpl.this.elementClassification ) {
|
||||
case EMBEDDED: {
|
||||
return ValueClassification.EMBEDDABLE;
|
||||
}
|
||||
case BASIC: {
|
||||
return ValueClassification.BASIC;
|
||||
}
|
||||
default: {
|
||||
return ValueClassification.ENTITY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AttributeMetadata getAttributeMetadata() {
|
||||
return PluralAttributeMetadataImpl.this;
|
||||
}
|
||||
};
|
||||
|
||||
// interpret the key, if one
|
||||
if ( this.listIndexOrMapKeyClassification != null ) {
|
||||
this.keyValueContext = new ValueContext() {
|
||||
public Value getHibernateValue() {
|
||||
return ( (Map) getPropertyMapping().getValue() ).getIndex();
|
||||
}
|
||||
|
||||
public Class getJpaBindableType() {
|
||||
return keyJavaType;
|
||||
}
|
||||
|
||||
public ValueClassification getValueClassification() {
|
||||
switch ( PluralAttributeMetadataImpl.this.listIndexOrMapKeyClassification ) {
|
||||
case EMBEDDED: {
|
||||
return ValueClassification.EMBEDDABLE;
|
||||
}
|
||||
case BASIC: {
|
||||
return ValueClassification.BASIC;
|
||||
}
|
||||
default: {
|
||||
return ValueClassification.ENTITY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AttributeMetadata getAttributeMetadata() {
|
||||
return PluralAttributeMetadataImpl.this;
|
||||
}
|
||||
};
|
||||
}
|
||||
else {
|
||||
keyValueContext = null;
|
||||
}
|
||||
}
|
||||
|
||||
private Class<?> getClassFromGenericArgument(java.lang.reflect.Type type) {
|
||||
if ( type instanceof Class ) {
|
||||
return (Class) type;
|
||||
}
|
||||
else if ( type instanceof TypeVariable ) {
|
||||
final java.lang.reflect.Type upperBound = ( (TypeVariable) type ).getBounds()[0];
|
||||
return getClassFromGenericArgument( upperBound );
|
||||
}
|
||||
else if ( type instanceof ParameterizedType ) {
|
||||
final java.lang.reflect.Type rawType = ( (ParameterizedType) type ).getRawType();
|
||||
return getClassFromGenericArgument( rawType );
|
||||
}
|
||||
else if ( type instanceof WildcardType ) {
|
||||
final java.lang.reflect.Type upperBound = ( (WildcardType) type ).getUpperBounds()[0];
|
||||
return getClassFromGenericArgument( upperBound );
|
||||
}
|
||||
else {
|
||||
throw new AssertionFailure(
|
||||
"Fail to process type argument in a generic declaration. Member : " + getMemberDescription()
|
||||
+ " Type: " + type.getClass()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static CollectionClassification determineCollectionType(Class javaType, Property property) {
|
||||
final Collection collection = (Collection) property.getValue();
|
||||
|
||||
if ( java.util.List.class.isAssignableFrom( javaType ) ) {
|
||||
return CollectionClassification.LIST;
|
||||
}
|
||||
else if ( java.util.Set.class.isAssignableFrom( javaType ) ) {
|
||||
if ( collection.isSorted() ) {
|
||||
return CollectionClassification.SORTED_SET;
|
||||
}
|
||||
|
||||
if ( collection.hasOrder() ) {
|
||||
return CollectionClassification.ORDERED_SET;
|
||||
}
|
||||
|
||||
return CollectionClassification.SET;
|
||||
}
|
||||
else if ( java.util.Map.class.isAssignableFrom( javaType ) ) {
|
||||
if ( collection.isSorted() ) {
|
||||
return CollectionClassification.SORTED_MAP;
|
||||
}
|
||||
|
||||
if ( collection.hasOrder() ) {
|
||||
return CollectionClassification.ORDERED_MAP;
|
||||
}
|
||||
|
||||
return CollectionClassification.MAP;
|
||||
}
|
||||
else if ( java.util.Collection.class.isAssignableFrom( javaType ) ) {
|
||||
if ( collection.isIdentified() ) {
|
||||
return CollectionClassification.IDBAG;
|
||||
}
|
||||
|
||||
return CollectionClassification.BAG;
|
||||
}
|
||||
else if ( javaType.isArray() ) {
|
||||
return CollectionClassification.ARRAY;
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException( "Expecting collection type [" + javaType.getName() + "]" );
|
||||
}
|
||||
}
|
||||
|
||||
public ValueContext getElementValueContext() {
|
||||
return elementValueContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionClassification getCollectionClassification() {
|
||||
return collectionClassification;
|
||||
}
|
||||
|
||||
public ValueContext getMapKeyValueContext() {
|
||||
return keyValueContext;
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.internal;
|
||||
|
||||
/**
|
||||
* Attribute metadata contract for a non-plural attribute.
|
||||
*
|
||||
* @param <X> The owner type
|
||||
* @param <Y> The attribute type
|
||||
*/
|
||||
public interface SingularAttributeMetadata<X, Y> extends AttributeMetadata<X, Y> {
|
||||
/**
|
||||
* Retrieve the value context for this attribute
|
||||
*
|
||||
* @return The attributes value context
|
||||
*/
|
||||
ValueContext getValueContext();
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.internal;
|
||||
|
||||
import java.lang.reflect.Member;
|
||||
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.metamodel.AttributeClassification;
|
||||
import org.hibernate.metamodel.ValueClassification;
|
||||
import org.hibernate.metamodel.model.domain.ManagedDomainType;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SingularAttributeMetadataImpl<X, Y> extends BaseAttributeMetadata<X, Y>
|
||||
implements SingularAttributeMetadata<X, Y> {
|
||||
private final ValueContext valueContext;
|
||||
|
||||
SingularAttributeMetadataImpl(
|
||||
Property propertyMapping,
|
||||
ManagedDomainType<X> ownerType,
|
||||
Member member,
|
||||
AttributeClassification attributeClassification,
|
||||
MetadataContext metadataContext) {
|
||||
super( propertyMapping, ownerType, member, attributeClassification, metadataContext );
|
||||
valueContext = new ValueContext() {
|
||||
public Value getHibernateValue() {
|
||||
return getPropertyMapping().getValue();
|
||||
}
|
||||
|
||||
public Class getJpaBindableType() {
|
||||
return getAttributeMetadata().getJavaType();
|
||||
}
|
||||
|
||||
public ValueClassification getValueClassification() {
|
||||
switch ( attributeClassification ) {
|
||||
case EMBEDDED: {
|
||||
return ValueClassification.EMBEDDABLE;
|
||||
}
|
||||
case BASIC: {
|
||||
return ValueClassification.BASIC;
|
||||
}
|
||||
default: {
|
||||
return ValueClassification.ENTITY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AttributeMetadata getAttributeMetadata() {
|
||||
return SingularAttributeMetadataImpl.this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public ValueContext getValueContext() {
|
||||
return valueContext;
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.internal;
|
||||
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.metamodel.ValueClassification;
|
||||
|
||||
/**
|
||||
* A contract for defining the meta information about a {@link Value}
|
||||
*/
|
||||
public interface ValueContext {
|
||||
ValueClassification getValueClassification();
|
||||
|
||||
Value getHibernateValue();
|
||||
|
||||
Class getJpaBindableType();
|
||||
|
||||
AttributeMetadata getAttributeMetadata();
|
||||
}
|
@ -10,12 +10,6 @@
|
||||
import java.util.Collection;
|
||||
|
||||
import org.hibernate.metamodel.CollectionClassification;
|
||||
import org.hibernate.metamodel.ValueClassification;
|
||||
import org.hibernate.metamodel.model.domain.AbstractManagedType;
|
||||
import org.hibernate.metamodel.model.domain.AnyMappingDomainType;
|
||||
import org.hibernate.metamodel.model.domain.BasicDomainType;
|
||||
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
|
||||
import org.hibernate.metamodel.model.domain.SimpleDomainType;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
@ -37,14 +31,6 @@ public abstract class AbstractPluralAttribute<D,C,E>
|
||||
extends AbstractAttribute<D,C,E>
|
||||
implements PluralPersistentAttribute<D,C,E>, Serializable {
|
||||
|
||||
public static <X,C,E,K> PluralAttributeBuilder<X,C,E,K> create(
|
||||
AbstractManagedType<X> ownerType,
|
||||
SimpleDomainType<E> attrType,
|
||||
JavaTypeDescriptor<C> collectionClass,
|
||||
SimpleDomainType<K> listIndexOrMapKeyType) {
|
||||
return new PluralAttributeBuilder<>( ownerType, attrType, collectionClass, listIndexOrMapKeyType );
|
||||
}
|
||||
|
||||
private final CollectionClassification classification;
|
||||
private final SqmPathSource<E> elementPathSource;
|
||||
|
||||
@ -62,35 +48,12 @@ protected AbstractPluralAttribute(PluralAttributeBuilder<D,C,E,?> builder) {
|
||||
this.classification = builder.getCollectionClassification();
|
||||
|
||||
this.elementPathSource = DomainModelHelper.resolveSqmPathSource(
|
||||
interpretValueClassification( builder.getValueType() ),
|
||||
getName(),
|
||||
builder.getValueType(),
|
||||
BindableType.PLURAL_ATTRIBUTE
|
||||
);
|
||||
}
|
||||
|
||||
private ValueClassification interpretValueClassification(SimpleDomainType<E> valueType) {
|
||||
if ( valueType instanceof BasicDomainType ) {
|
||||
return ValueClassification.BASIC;
|
||||
}
|
||||
|
||||
if ( valueType instanceof AnyMappingDomainType ) {
|
||||
return ValueClassification.ANY;
|
||||
}
|
||||
|
||||
if ( valueType instanceof EmbeddableDomainType ) {
|
||||
return ValueClassification.EMBEDDED;
|
||||
}
|
||||
|
||||
if ( valueType instanceof EntityDomainType ) {
|
||||
return ValueClassification.ENTITY;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
"Unrecognized value type Java-type [" + valueType.getTypeName() + "] for plural attribute value"
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPathName() {
|
||||
return getName();
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
package org.hibernate.metamodel.model.domain.internal;
|
||||
|
||||
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
|
||||
import org.hibernate.metamodel.model.domain.AllowableParameterType;
|
||||
import org.hibernate.metamodel.model.domain.BasicDomainType;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
@ -18,7 +19,9 @@
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class BasicSqmPathSource<J> extends AbstractSqmPathSource<J> implements AllowableParameterType<J> {
|
||||
public class BasicSqmPathSource<J>
|
||||
extends AbstractSqmPathSource<J>
|
||||
implements AllowableParameterType<J>, AllowableFunctionReturnType<J> {
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public BasicSqmPathSource(
|
||||
String localPathName,
|
||||
@ -48,4 +51,14 @@ public SqmPath<J> createSqmPath(SqmPath<?> lhs, SqmCreationState creationState)
|
||||
creationState.getCreationContext().getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PersistenceType getPersistenceType() {
|
||||
return PersistenceType.BASIC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<J> getJavaType() {
|
||||
return getExpressableJavaTypeDescriptor().getJavaType();
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.ValueClassification;
|
||||
import org.hibernate.metamodel.model.domain.AnyMappingDomainType;
|
||||
import org.hibernate.metamodel.model.domain.BasicDomainType;
|
||||
import org.hibernate.metamodel.model.domain.DomainType;
|
||||
@ -80,42 +79,44 @@ public static EntityPersister resolveEntityPersister(
|
||||
}
|
||||
|
||||
public static <J> SqmPathSource<J> resolveSqmPathSource(
|
||||
ValueClassification classification,
|
||||
String name,
|
||||
DomainType<J> valueDomainType,
|
||||
Bindable.BindableType jpaBindableType) {
|
||||
switch ( classification ) {
|
||||
case BASIC: {
|
||||
return new BasicSqmPathSource<>(
|
||||
name,
|
||||
(BasicDomainType<J>) valueDomainType,
|
||||
jpaBindableType
|
||||
);
|
||||
}
|
||||
case ANY: {
|
||||
return new AnyMappingSqmPathSource<>(
|
||||
name,
|
||||
(AnyMappingDomainType<J>) valueDomainType,
|
||||
jpaBindableType
|
||||
);
|
||||
}
|
||||
case EMBEDDED: {
|
||||
return new EmbeddedSqmPathSource<>(
|
||||
name,
|
||||
(EmbeddableDomainType<J>) valueDomainType,
|
||||
jpaBindableType
|
||||
);
|
||||
}
|
||||
case ENTITY: {
|
||||
return new EntitySqmPathSource<>(
|
||||
name,
|
||||
(EntityDomainType<J>) valueDomainType,
|
||||
jpaBindableType
|
||||
);
|
||||
}
|
||||
default: {
|
||||
throw new IllegalArgumentException( "Unrecognized ValueClassification : " + classification );
|
||||
}
|
||||
|
||||
if ( valueDomainType instanceof BasicDomainType ) {
|
||||
return new BasicSqmPathSource<>(
|
||||
name,
|
||||
(BasicDomainType<J>) valueDomainType,
|
||||
jpaBindableType
|
||||
);
|
||||
}
|
||||
|
||||
if ( valueDomainType instanceof AnyMappingDomainType ) {
|
||||
return new AnyMappingSqmPathSource<>(
|
||||
name,
|
||||
(AnyMappingDomainType<J>) valueDomainType,
|
||||
jpaBindableType
|
||||
);
|
||||
}
|
||||
|
||||
if ( valueDomainType instanceof EmbeddableDomainType ) {
|
||||
return new EmbeddedSqmPathSource<>(
|
||||
name,
|
||||
(EmbeddableDomainType<J>) valueDomainType,
|
||||
jpaBindableType
|
||||
);
|
||||
}
|
||||
|
||||
if ( valueDomainType instanceof EntityDomainType ) {
|
||||
return new EntitySqmPathSource<>(
|
||||
name,
|
||||
(EntityDomainType<J>) valueDomainType,
|
||||
jpaBindableType
|
||||
);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
"Unrecognized value type Java-type [" + valueDomainType.getTypeName() + "] for plural attribute value"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
import org.hibernate.query.sqm.SqmPathSource;
|
||||
import org.hibernate.query.sqm.produce.spi.SqmCreationState;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmAnyValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
|
||||
/**
|
||||
@ -36,7 +37,7 @@ public SqmPathSource<?> findSubPathSource(String name) {
|
||||
|
||||
@Override
|
||||
public SqmPath<J> createSqmPath(SqmPath<?> lhs, SqmCreationState creationState) {
|
||||
return new SqmAnyValuedSimplePath<>(
|
||||
return new SqmEmbeddedValuedSimplePath<>(
|
||||
lhs.getNavigablePath().append( getPathName() ),
|
||||
this,
|
||||
lhs,
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.metamodel.ValueClassification;
|
||||
import org.hibernate.metamodel.model.domain.ListPersistentAttribute;
|
||||
import org.hibernate.query.sqm.SqmPathSource;
|
||||
import org.hibernate.query.sqm.produce.spi.SqmCreationState;
|
||||
@ -28,7 +27,6 @@ class ListAttributeImpl<X, E> extends AbstractPluralAttribute<X, List<E>, E> imp
|
||||
|
||||
//noinspection unchecked
|
||||
this.indexPathSource = (SqmPathSource) DomainModelHelper.resolveSqmPathSource(
|
||||
ValueClassification.BASIC,
|
||||
getName(),
|
||||
builder.getListIndexOrMapKeyType(),
|
||||
BindableType.PLURAL_ATTRIBUTE
|
||||
|
@ -9,7 +9,6 @@
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.metamodel.ValueClassification;
|
||||
import org.hibernate.metamodel.model.domain.MapPersistentAttribute;
|
||||
import org.hibernate.metamodel.model.domain.SimpleDomainType;
|
||||
import org.hibernate.query.sqm.SqmPathSource;
|
||||
@ -29,7 +28,6 @@ class MapAttributeImpl<X, K, V> extends AbstractPluralAttribute<X, Map<K, V>, V>
|
||||
super( xceBuilder );
|
||||
|
||||
this.keyPathSource = DomainModelHelper.resolveSqmPathSource(
|
||||
ValueClassification.BASIC,
|
||||
getName(),
|
||||
xceBuilder.getListIndexOrMapKeyType(),
|
||||
BindableType.PLURAL_ATTRIBUTE
|
||||
@ -51,6 +49,11 @@ public SqmPathSource getKeyPathSource() {
|
||||
return keyPathSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPathSource getIndexPathSource() {
|
||||
return getKeyPathSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleDomainType<K> getKeyType() {
|
||||
return (SimpleDomainType<K>) keyPathSource.getSqmPathType();
|
||||
|
@ -15,35 +15,130 @@
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.metamodel.AttributeClassification;
|
||||
import org.hibernate.metamodel.CollectionClassification;
|
||||
import org.hibernate.metamodel.internal.AttributeFactory;
|
||||
import org.hibernate.metamodel.internal.MetadataContext;
|
||||
import org.hibernate.metamodel.internal.PluralAttributeMetadata;
|
||||
import org.hibernate.metamodel.model.domain.ManagedDomainType;
|
||||
import org.hibernate.metamodel.model.domain.PersistentAttribute;
|
||||
import org.hibernate.metamodel.model.domain.SimpleDomainType;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
||||
import static org.hibernate.metamodel.internal.AttributeFactory.determineSimpleType;
|
||||
|
||||
/**
|
||||
* A "parameter object" for creating a plural attribute
|
||||
*/
|
||||
public class PluralAttributeBuilder<D, C, E, K> {
|
||||
private final JavaTypeDescriptor<C> collectionJtd;
|
||||
|
||||
private final AttributeClassification attributeClassification;
|
||||
private final CollectionClassification collectionClassification;
|
||||
|
||||
private final SimpleDomainType<E> elementType;
|
||||
private final SimpleDomainType<K> listIndexOrMapKeyType;
|
||||
|
||||
private final ManagedDomainType<D> declaringType;
|
||||
private final SimpleDomainType<E> valueType;
|
||||
|
||||
private SimpleDomainType<K> listIndexOrMapKeyType;
|
||||
|
||||
private AttributeClassification attributeClassification;
|
||||
private CollectionClassification collectionClassification;
|
||||
private JavaTypeDescriptor<C> collectionJavaTypeDescriptor;
|
||||
|
||||
private Property property;
|
||||
private Member member;
|
||||
private final Property property;
|
||||
private final Member member;
|
||||
|
||||
public PluralAttributeBuilder(
|
||||
ManagedDomainType<D> ownerType,
|
||||
JavaTypeDescriptor<C> collectionJtd,
|
||||
AttributeClassification attributeClassification,
|
||||
CollectionClassification collectionClassification,
|
||||
SimpleDomainType<E> elementType,
|
||||
JavaTypeDescriptor<C> collectionJavaTypeDescriptor,
|
||||
SimpleDomainType<K> listIndexOrMapKeyType) {
|
||||
this.declaringType = ownerType;
|
||||
this.valueType = elementType;
|
||||
this.collectionJavaTypeDescriptor = collectionJavaTypeDescriptor;
|
||||
SimpleDomainType<K> listIndexOrMapKeyType,
|
||||
ManagedDomainType<D> declaringType,
|
||||
Property property,
|
||||
Member member) {
|
||||
this.collectionJtd = collectionJtd;
|
||||
this.attributeClassification = attributeClassification;
|
||||
this.collectionClassification = collectionClassification;
|
||||
this.elementType = elementType;
|
||||
this.listIndexOrMapKeyType = listIndexOrMapKeyType;
|
||||
this.declaringType = declaringType;
|
||||
this.property = property;
|
||||
this.member = member;
|
||||
}
|
||||
|
||||
public static <Y, X> PersistentAttribute<X, Y> build(
|
||||
PluralAttributeMetadata<?,Y,?> attributeMetadata,
|
||||
MetadataContext metadataContext) {
|
||||
|
||||
final JavaTypeDescriptor<Y> attributeJtd = metadataContext.getTypeConfiguration()
|
||||
.getJavaTypeDescriptorRegistry()
|
||||
.getDescriptor( attributeMetadata.getJavaType() );
|
||||
|
||||
//noinspection unchecked
|
||||
final PluralAttributeBuilder builder = new PluralAttributeBuilder(
|
||||
attributeJtd,
|
||||
attributeMetadata.getAttributeClassification(),
|
||||
attributeMetadata.getCollectionClassification(),
|
||||
AttributeFactory.determineSimpleType(
|
||||
attributeMetadata.getElementValueContext(),
|
||||
metadataContext
|
||||
),
|
||||
determineListIndexOrMapKeyType( attributeMetadata, metadataContext ),
|
||||
attributeMetadata.getOwnerType(),
|
||||
attributeMetadata.getPropertyMapping(),
|
||||
attributeMetadata.getMember()
|
||||
);
|
||||
|
||||
if ( Map.class.equals( attributeJtd.getJavaType() ) ) {
|
||||
//noinspection unchecked
|
||||
return new MapAttributeImpl<>( builder );
|
||||
}
|
||||
else if ( Set.class.equals( attributeJtd.getJavaType() ) ) {
|
||||
//noinspection unchecked
|
||||
return new SetAttributeImpl<>( builder );
|
||||
}
|
||||
else if ( List.class.equals( attributeJtd.getJavaType() ) ) {
|
||||
//noinspection unchecked
|
||||
return new ListAttributeImpl<>( builder );
|
||||
}
|
||||
else if ( Collection.class.equals( attributeJtd.getJavaType() ) ) {
|
||||
//noinspection unchecked
|
||||
return new BagAttributeImpl<>( builder );
|
||||
}
|
||||
|
||||
//apply loose rules
|
||||
if ( attributeJtd.getJavaType().isArray() ) {
|
||||
//noinspection unchecked
|
||||
return new ListAttributeImpl<>( builder );
|
||||
}
|
||||
|
||||
if ( Map.class.isAssignableFrom( attributeJtd.getJavaType() ) ) {
|
||||
//noinspection unchecked
|
||||
return new MapAttributeImpl<>( builder );
|
||||
}
|
||||
else if ( Set.class.isAssignableFrom( attributeJtd.getJavaType() ) ) {
|
||||
//noinspection unchecked
|
||||
return new SetAttributeImpl<>( builder );
|
||||
}
|
||||
else if ( List.class.isAssignableFrom( attributeJtd.getJavaType() ) ) {
|
||||
//noinspection unchecked
|
||||
return new ListAttributeImpl<>( builder );
|
||||
}
|
||||
else if ( Collection.class.isAssignableFrom( attributeJtd.getJavaType() ) ) {
|
||||
//noinspection unchecked
|
||||
return new BagAttributeImpl<>( builder );
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException( "Unknown collection: " + attributeJtd.getJavaType() );
|
||||
}
|
||||
|
||||
private static SimpleDomainType<?> determineListIndexOrMapKeyType(
|
||||
PluralAttributeMetadata<?,?,?> attributeMetadata,
|
||||
MetadataContext metadataContext) {
|
||||
if ( java.util.Map.class.isAssignableFrom( attributeMetadata.getJavaType() ) ) {
|
||||
return determineSimpleType( attributeMetadata.getMapKeyValueContext(), metadataContext );
|
||||
}
|
||||
|
||||
if ( java.util.List.class.isAssignableFrom( attributeMetadata.getJavaType() ) ) {
|
||||
return metadataContext.getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( Integer.class );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public ManagedDomainType<D> getDeclaringType() {
|
||||
@ -63,11 +158,11 @@ public SimpleDomainType<K> getListIndexOrMapKeyType() {
|
||||
}
|
||||
|
||||
public JavaTypeDescriptor<C> getCollectionJavaTypeDescriptor() {
|
||||
return collectionJavaTypeDescriptor;
|
||||
return collectionJtd;
|
||||
}
|
||||
|
||||
public SimpleDomainType<E> getValueType() {
|
||||
return valueType;
|
||||
return elementType;
|
||||
}
|
||||
|
||||
public Property getProperty() {
|
||||
@ -77,82 +172,4 @@ public Property getProperty() {
|
||||
public Member getMember() {
|
||||
return member;
|
||||
}
|
||||
|
||||
public PluralAttributeBuilder<D,C,E,K> member(Member member) {
|
||||
this.member = member;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PluralAttributeBuilder<D,C,E,K> property(Property property) {
|
||||
this.property = property;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PluralAttributeBuilder<D,C,E,K> persistentAttributeClassification(AttributeClassification classification) {
|
||||
this.attributeClassification = classification;
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings( "unchecked" )
|
||||
public AbstractPluralAttribute<D,C,E> build() {
|
||||
//apply strict spec rules first
|
||||
if ( Map.class.equals( collectionJavaTypeDescriptor.getJavaType() ) ) {
|
||||
final PluralAttributeBuilder<D,Map<K,E>,E,K> builder = (PluralAttributeBuilder<D,Map<K,E>,E,K>) this;
|
||||
return (AbstractPluralAttribute<D, C, E>) new MapAttributeImpl<>(
|
||||
builder
|
||||
);
|
||||
}
|
||||
else if ( Set.class.equals( collectionJavaTypeDescriptor.getJavaType() ) ) {
|
||||
final PluralAttributeBuilder<D,Set<E>, E,?> builder = (PluralAttributeBuilder<D, Set<E>, E,?>) this;
|
||||
return (AbstractPluralAttribute<D, C, E>) new SetAttributeImpl<>(
|
||||
builder
|
||||
);
|
||||
}
|
||||
else if ( List.class.equals( collectionJavaTypeDescriptor.getJavaType() ) ) {
|
||||
final PluralAttributeBuilder<D, List<E>, E,?> builder = (PluralAttributeBuilder<D, List<E>, E,?>) this;
|
||||
return (AbstractPluralAttribute<D, C, E>) new ListAttributeImpl<>(
|
||||
builder
|
||||
);
|
||||
}
|
||||
else if ( Collection.class.equals( collectionJavaTypeDescriptor.getJavaType() ) ) {
|
||||
final PluralAttributeBuilder<D, Collection<E>,E,?> builder = (PluralAttributeBuilder<D, Collection<E>, E,?>) this;
|
||||
return (AbstractPluralAttribute<D, C, E>) new BagAttributeImpl<>(
|
||||
builder
|
||||
);
|
||||
}
|
||||
|
||||
//apply loose rules
|
||||
if ( collectionJavaTypeDescriptor.getJavaType().isArray() ) {
|
||||
final PluralAttributeBuilder<D, List<E>, E,?> builder = (PluralAttributeBuilder<D, List<E>, E,?>) this;
|
||||
return (AbstractPluralAttribute<D, C, E>) new ListAttributeImpl<>(
|
||||
builder
|
||||
);
|
||||
}
|
||||
|
||||
if ( Map.class.isAssignableFrom( collectionJavaTypeDescriptor.getJavaType() ) ) {
|
||||
final PluralAttributeBuilder<D,Map<K,E>,E,K> builder = (PluralAttributeBuilder<D,Map<K,E>,E,K>) this;
|
||||
return (AbstractPluralAttribute<D, C, E>) new MapAttributeImpl<>(
|
||||
builder
|
||||
);
|
||||
}
|
||||
else if ( Set.class.isAssignableFrom( collectionJavaTypeDescriptor.getJavaType() ) ) {
|
||||
final PluralAttributeBuilder<D,Set<E>, E,?> builder = (PluralAttributeBuilder<D, Set<E>, E,?>) this;
|
||||
return (AbstractPluralAttribute<D, C, E>) new SetAttributeImpl<>(
|
||||
builder
|
||||
);
|
||||
}
|
||||
else if ( List.class.isAssignableFrom( collectionJavaTypeDescriptor.getJavaType() ) ) {
|
||||
final PluralAttributeBuilder<D, List<E>, E,?> builder = (PluralAttributeBuilder<D, List<E>, E,?>) this;
|
||||
return (AbstractPluralAttribute<D, C, E>) new ListAttributeImpl<>(
|
||||
builder
|
||||
);
|
||||
}
|
||||
else if ( Collection.class.isAssignableFrom( collectionJavaTypeDescriptor.getJavaType() ) ) {
|
||||
final PluralAttributeBuilder<D, Collection<E>,E,?> builder = (PluralAttributeBuilder<D, Collection<E>, E,?>) this;
|
||||
return (AbstractPluralAttribute<D, C, E>) new BagAttributeImpl<>(
|
||||
builder
|
||||
);
|
||||
}
|
||||
throw new UnsupportedOperationException( "Unknown collection: " + collectionJavaTypeDescriptor.getJavaType() );
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,6 @@
|
||||
|
||||
import org.hibernate.graph.spi.GraphHelper;
|
||||
import org.hibernate.metamodel.AttributeClassification;
|
||||
import org.hibernate.metamodel.ValueClassification;
|
||||
import org.hibernate.metamodel.model.domain.ManagedDomainType;
|
||||
import org.hibernate.metamodel.model.domain.SimpleDomainType;
|
||||
import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
|
||||
@ -57,36 +56,12 @@ public SingularAttributeImpl(
|
||||
|
||||
|
||||
this.sqmPathSource = DomainModelHelper.resolveSqmPathSource(
|
||||
determineValueClassification( attributeClassification ),
|
||||
name,
|
||||
attributeType,
|
||||
BindableType.SINGULAR_ATTRIBUTE
|
||||
);
|
||||
}
|
||||
|
||||
private static ValueClassification determineValueClassification(AttributeClassification attributeClassification) {
|
||||
switch ( attributeClassification ) {
|
||||
case BASIC: {
|
||||
return ValueClassification.BASIC;
|
||||
}
|
||||
case ANY: {
|
||||
return ValueClassification.ANY;
|
||||
}
|
||||
case EMBEDDED: {
|
||||
return ValueClassification.EMBEDDED;
|
||||
}
|
||||
case ONE_TO_ONE:
|
||||
case MANY_TO_ONE: {
|
||||
return ValueClassification.ENTITY;
|
||||
}
|
||||
default: {
|
||||
throw new IllegalArgumentException(
|
||||
"Unrecognized AttributeClassification (for singular attribute): " + attributeClassification
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPathName() {
|
||||
return getName();
|
||||
|
@ -1879,7 +1879,7 @@ public SqmExpression visitFloorFunction(HqlParser.FloorFunctionContext ctx) {
|
||||
}
|
||||
|
||||
private SqmFunctionTemplate getFunctionTemplate(String name) {
|
||||
return creationContext.getQueryEngine().getSqmFunctionRegistry().findFunctionTemplate(name);
|
||||
return creationContext.getQueryEngine().getSqmFunctionRegistry().findFunctionTemplate( name );
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -2752,12 +2752,12 @@ private SqmTreatedPath resolveTreatedPath(SqmPath<?> sqmPath, EntityDomainType<?
|
||||
|
||||
@Override
|
||||
public SqmPath<?> visitCollectionElementNavigablePath(HqlParser.CollectionElementNavigablePathContext ctx) {
|
||||
final SqmPath<?> sqmPath = consumeManagedTypeReference( ctx.path() );
|
||||
final SqmPathSource<?> referencedPathSource = sqmPath.getReferencedPathSource();
|
||||
final SqmPath<?> pluralAttributePath = consumeDomainPath( ctx.path() );
|
||||
final SqmPathSource<?> referencedPathSource = pluralAttributePath.getReferencedPathSource();
|
||||
|
||||
if ( !(referencedPathSource instanceof PluralPersistentAttribute ) ) {
|
||||
throw new PathException(
|
||||
"Illegal attempt to treat non-plural path as a plural path : " + sqmPath.getNavigablePath()
|
||||
"Illegal attempt to treat non-plural path as a plural path : " + pluralAttributePath.getNavigablePath()
|
||||
);
|
||||
}
|
||||
|
||||
@ -2770,7 +2770,7 @@ public SqmPath<?> visitCollectionElementNavigablePath(HqlParser.CollectionElemen
|
||||
}
|
||||
|
||||
SqmPath result = attribute.getElementPathSource().createSqmPath(
|
||||
sqmPath,
|
||||
pluralAttributePath,
|
||||
this
|
||||
);
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
import org.hibernate.query.sqm.produce.spi.SqmCreationState;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmNavigableReference;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmSimplePath;
|
||||
|
||||
/**
|
||||
* @asciidoc
|
||||
@ -20,7 +20,7 @@
|
||||
* * class name
|
||||
* * field name
|
||||
* * enum name
|
||||
* * {@link SqmNavigableReference}
|
||||
* * {@link SqmSimplePath}
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -21,6 +21,8 @@
|
||||
import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
||||
|
||||
/**
|
||||
* Specialized CASE statement for resolving the first non-null value in a list of values
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Gavin King
|
||||
*/
|
||||
|
@ -20,7 +20,7 @@
|
||||
import org.hibernate.query.sqm.mutation.spi.UpdateHandler;
|
||||
import org.hibernate.query.sqm.tree.SqmDeleteOrUpdateStatement;
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmNavigableReference;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmSimplePath;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
||||
import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate;
|
||||
import org.hibernate.query.sqm.tree.predicate.SqmGroupedPredicate;
|
||||
@ -197,7 +197,7 @@ public static boolean hasNonIdReferences(SqmPredicate predicate) {
|
||||
* Is the given `expression` a `SqmNavigableReference` that is also a reference
|
||||
* to a non-`EntityIdentifier` `Navigable`?
|
||||
*
|
||||
* @see SqmNavigableReference
|
||||
* @see SqmSimplePath
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public static boolean isNonIdentifierReference(SqmExpression expression) {
|
||||
|
@ -6,7 +6,10 @@
|
||||
*/
|
||||
package org.hibernate.query.sqm.tree.domain;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
@ -95,6 +98,15 @@ public SqmPath<?> getLhs() {
|
||||
return lhs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SqmPath<?>> getImplicitJoinPaths() {
|
||||
if ( implicitJoinPaths == null ) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return new ArrayList<>( implicitJoinPaths.values() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitImplicitJoinPaths(Consumer<SqmPath<?>> consumer) {
|
||||
if ( implicitJoinPaths != null ) {
|
||||
|
@ -13,7 +13,7 @@
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractSqmSimplePath<T> extends AbstractSqmPath<T> implements SqmNavigableReference<T> {
|
||||
public abstract class AbstractSqmSimplePath<T> extends AbstractSqmPath<T> implements SqmSimplePath<T> {
|
||||
private final NavigablePath navigablePath;
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
|
@ -57,6 +57,10 @@ public String getAlias() {
|
||||
return explicitAlias;
|
||||
}
|
||||
|
||||
public SqmPath<?> getMapPath() {
|
||||
return mapPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaSelection<Map.Entry<K, V>> alias(String name) {
|
||||
this.explicitAlias = name;
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
package org.hibernate.query.sqm.tree.domain;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
@ -63,6 +64,11 @@ public interface SqmPath<T> extends SqmExpression<T>, SemanticPathPart, JpaPath<
|
||||
*/
|
||||
SqmPath<?> getLhs();
|
||||
|
||||
/**
|
||||
* Returns an immutable List of implicit-join paths
|
||||
*/
|
||||
List<SqmPath<?>> getImplicitJoinPaths();
|
||||
|
||||
/**
|
||||
* Visit each implicit-join path relative to this path
|
||||
*/
|
||||
|
@ -12,5 +12,5 @@
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface SqmNavigableReference<T> extends SqmPath<T> {
|
||||
public interface SqmSimplePath<T> extends SqmPath<T> {
|
||||
}
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
public class SqmTreatedSimplePath<T, S extends T>
|
||||
extends SqmEntityValuedSimplePath<S>
|
||||
implements SqmNavigableReference<S>, SqmTreatedPath<T,S> {
|
||||
implements SqmSimplePath<S>, SqmTreatedPath<T,S> {
|
||||
|
||||
private final EntityDomainType<S> treatTarget;
|
||||
private final SqmPath<T> wrappedPath;
|
||||
|
@ -11,7 +11,7 @@
|
||||
import org.hibernate.orm.test.query.sqm.BaseSqmUnitTest;
|
||||
import org.hibernate.query.sqm.AliasCollisionException;
|
||||
import org.hibernate.query.sqm.produce.spi.ImplicitAliasGenerator;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmNavigableReference;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmSimplePath;
|
||||
import org.hibernate.query.sqm.tree.from.SqmRoot;
|
||||
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
|
||||
import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate;
|
||||
@ -143,12 +143,12 @@ public void testSubqueryUsingIdentificationVariableDefinedInRootQuery() {
|
||||
);
|
||||
|
||||
final SqmComparisonPredicate correlation = (SqmComparisonPredicate) subQuerySpec.getWhereClause().getPredicate();
|
||||
final SqmNavigableReference leftHandExpression = (SqmNavigableReference) correlation.getLeftHandExpression();
|
||||
final SqmSimplePath leftHandExpression = (SqmSimplePath) correlation.getLeftHandExpression();
|
||||
assertThat(
|
||||
leftHandExpression.getLhs().getExplicitAlias(),
|
||||
is( "a" )
|
||||
);
|
||||
final SqmNavigableReference rightHandExpression = (SqmNavigableReference) correlation.getRightHandExpression();
|
||||
final SqmSimplePath rightHandExpression = (SqmSimplePath) correlation.getRightHandExpression();
|
||||
assertThat(
|
||||
rightHandExpression.getLhs().getExplicitAlias(),
|
||||
is( "b" )
|
||||
|
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.query.hql;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.orm.test.query.sqm.BaseSqmUnitTest;
|
||||
import org.hibernate.orm.test.query.sqm.domain.Person;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmEntityValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
||||
import org.hibernate.query.sqm.tree.from.SqmRoot;
|
||||
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelection;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public class AttributePathTests extends BaseSqmUnitTest {
|
||||
|
||||
@Override
|
||||
protected Class[] getAnnotatedClasses() {
|
||||
return new Class[] { Person.class };
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImplicitJoinReuse() {
|
||||
final SqmSelectStatement statement = interpretSelect( "select s.mate.dob, s.mate.numberOfToes from Person s" );
|
||||
|
||||
assertThat( statement.getQuerySpec().getFromClause().getRoots().size(), is(1) );
|
||||
final SqmRoot sqmRoot = statement.getQuerySpec().getFromClause().getRoots().get( 0 );
|
||||
|
||||
assertThat( sqmRoot.getJoins().size(), is(0) );
|
||||
assertThat( sqmRoot.getImplicitJoinPaths().size(), is(1) );
|
||||
|
||||
// from-clause paths
|
||||
// assertPropertyPath( space.getRoot(), "com.acme.Something(s)" );
|
||||
// assertPropertyPath( space.getJoins().get( 0 ), "com.acme.Something(s).entity" );
|
||||
|
||||
final List<SqmSelection> selections = statement.getQuerySpec().getSelectClause().getSelections();
|
||||
assertThat( selections.size(), is(2) );
|
||||
|
||||
// expression paths
|
||||
assertPropertyPath( (SqmExpression) selections.get( 0 ).getSelectableNode(), Person.class.getName() + "(s).mate.dob" );
|
||||
assertPropertyPath( (SqmExpression) selections.get( 1 ).getSelectableNode(), Person.class.getName() + "(s).mate.numberOfToes" );
|
||||
}
|
||||
|
||||
private void assertPropertyPath(SqmExpression expression, String expectedFullPath) {
|
||||
assertThat( expression, instanceOf( SqmSimplePath.class ) );
|
||||
final SqmSimplePath domainReferenceBinding = (SqmSimplePath) expression;
|
||||
assertThat( domainReferenceBinding.getNavigablePath().getFullPath(), is( expectedFullPath) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImplicitJoinReuse2() {
|
||||
final SqmSelectStatement statement = interpretSelect( "select s.mate from Person s where s.mate.dob = ?1" );
|
||||
|
||||
assertThat( statement.getQuerySpec().getFromClause().getRoots().size(), is(1) );
|
||||
final SqmRoot sqmRoot = statement.getQuerySpec().getFromClause().getRoots().get( 0 );
|
||||
|
||||
assertThat( sqmRoot.getJoins().size(), is(0) );
|
||||
assertThat( sqmRoot.getImplicitJoinPaths().size(), is(1) );
|
||||
|
||||
final SqmSelection selection = statement.getQuerySpec().getSelectClause().getSelections().get( 0 );
|
||||
assertThat( selection.getSelectableNode(), instanceOf( SqmEntityValuedSimplePath.class ) );
|
||||
|
||||
final SqmPath selectExpression = (SqmPath) selection.getSelectableNode();
|
||||
assertThat( selectExpression.getReferencedPathSource().getSqmPathType(), instanceOf( EntityDomainType.class ) );
|
||||
|
||||
final SqmComparisonPredicate predicate = (SqmComparisonPredicate) statement.getQuerySpec().getWhereClause().getPredicate();
|
||||
final SqmPath predicateLhs = (SqmPath) predicate.getLeftHandExpression();
|
||||
assertThat( predicateLhs.getLhs(), notNullValue() );
|
||||
|
||||
|
||||
// from-clause paths
|
||||
// assertPropertyPath( space.getRoot(), "com.acme.Something(s)" );
|
||||
// assertPropertyPath( space.getJoins().get( 0 ), "com.acme.Something(s).entity" );
|
||||
|
||||
// expression paths
|
||||
assertPropertyPath( (SqmExpression) selection.getSelectableNode(), Person.class.getName() + "(s).mate" );
|
||||
assertPropertyPath( predicateLhs, Person.class.getName() + "(s).mate.dob" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEntityIdReferences() {
|
||||
interpretSelect( "select s.mate from Person s where s.id = ?1" );
|
||||
interpretSelect( "select s.mate from Person s where s.{id} = ?1" );
|
||||
interpretSelect( "select s.mate from Person s where s.pk = ?1" );
|
||||
}
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.query.hql;
|
||||
|
||||
import org.hibernate.orm.test.query.sqm.BaseSqmUnitTest;
|
||||
import org.hibernate.orm.test.query.sqm.domain.Person;
|
||||
import org.hibernate.query.sqm.function.SqmCoalesce;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
|
||||
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
|
||||
|
||||
import org.hibernate.testing.orm.junit.TestingUtil;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hibernate.testing.hamcrest.CollectionMatchers.hasSize;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public class CaseExpressionsTest extends BaseSqmUnitTest {
|
||||
|
||||
@Override
|
||||
protected Class[] getAnnotatedClasses() {
|
||||
return new Class[] { Person.class };
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicSimpleCaseExpression() {
|
||||
SqmSelectStatement select = interpretSelect(
|
||||
"select p from Person p where p.numberOfToes = case p.dob when ?1 then 6 else 8 end"
|
||||
);
|
||||
|
||||
final SqmComparisonPredicate predicate = TestingUtil.cast(
|
||||
select.getQuerySpec().getWhereClause().getPredicate(),
|
||||
SqmComparisonPredicate.class
|
||||
);
|
||||
|
||||
final SqmCaseSimple caseStatement = TestingUtil.cast(
|
||||
predicate.getRightHandExpression(),
|
||||
SqmCaseSimple.class
|
||||
);
|
||||
|
||||
assertThat( caseStatement.getFixture(), notNullValue() );
|
||||
assertThat( caseStatement.getFixture(), instanceOf( SqmPath.class ) );
|
||||
|
||||
assertThat( caseStatement.getOtherwise(), notNullValue() );
|
||||
assertThat( caseStatement.getOtherwise(), instanceOf( SqmLiteral.class ) );
|
||||
|
||||
assertThat( caseStatement.getWhenFragments().size(), is(1) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicSearchedCaseExpression() {
|
||||
SqmSelectStatement select = interpretSelect(
|
||||
"select p from Person p where p.numberOfToes = case when p.dob = ?1 then 6 else 8 end"
|
||||
);
|
||||
|
||||
final SqmComparisonPredicate predicate = TestingUtil.cast(
|
||||
select.getQuerySpec().getWhereClause().getPredicate(),
|
||||
SqmComparisonPredicate.class
|
||||
);
|
||||
|
||||
final SqmCaseSearched caseStatement = TestingUtil.cast(
|
||||
predicate.getRightHandExpression(),
|
||||
SqmCaseSearched.class
|
||||
);
|
||||
|
||||
assertThat( caseStatement.getOtherwise(), notNullValue() );
|
||||
assertThat( caseStatement.getOtherwise(), instanceOf( SqmLiteral.class ) );
|
||||
|
||||
assertThat( caseStatement.getWhenFragments().size(), is(1) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicCoalesceExpression() {
|
||||
SqmSelectStatement select = interpretSelect(
|
||||
"select coalesce(p.nickName, p.mate.nickName) from Person p"
|
||||
);
|
||||
|
||||
assertThat( select.getQuerySpec().getSelectClause().getSelections(), hasSize( 1 ) );
|
||||
|
||||
final SqmCoalesce<?> coalesce = TestingUtil.cast(
|
||||
select.getQuerySpec().getSelectClause().getSelections().get( 0 ).getSelectableNode(),
|
||||
SqmCoalesce.class
|
||||
);
|
||||
|
||||
assertThat( coalesce.getArguments(), hasSize( 2 ) );
|
||||
assertEquals( coalesce.getJavaTypeDescriptor().getJavaType(), String.class );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicNullifExpression() {
|
||||
SqmSelectStatement select = interpretSelect(
|
||||
"select nullif(p.nickName, p.mate.nickName) from Person p"
|
||||
);
|
||||
|
||||
assertThat( select.getQuerySpec().getSelectClause().getSelections(), hasSize( 1 ) );
|
||||
final SqmSelectableNode<?> selectableNode = select.getQuerySpec()
|
||||
.getSelectClause()
|
||||
.getSelections()
|
||||
.get( 0 )
|
||||
.getSelectableNode();
|
||||
|
||||
assertEquals( selectableNode.getJavaTypeDescriptor().getJavaType(), String.class );
|
||||
|
||||
// final nullif = TestingUtil.cast(
|
||||
// selectableNode,
|
||||
// SqmNullifFunction.class
|
||||
// );
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.query.hql;
|
||||
|
||||
import org.hibernate.orm.test.query.sqm.BaseSqmUnitTest;
|
||||
import org.hibernate.orm.test.query.sqm.domain.Person;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class FunctionTests extends BaseSqmUnitTest {
|
||||
@Override
|
||||
protected Class[] getAnnotatedClasses() {
|
||||
return new Class[] { Person.class };
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,322 @@
|
||||
/*
|
||||
* 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 http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.query.hql;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.metamodel.CollectionClassification;
|
||||
import org.hibernate.metamodel.model.domain.BasicDomainType;
|
||||
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
|
||||
import org.hibernate.metamodel.model.domain.SimpleDomainType;
|
||||
import org.hibernate.orm.test.query.sqm.BaseSqmUnitTest;
|
||||
import org.hibernate.orm.test.query.sqm.domain.Person;
|
||||
import org.hibernate.query.sqm.SqmPathSource;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMapEntryReference;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmSimplePath;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmBinaryArithmetic;
|
||||
import org.hibernate.query.sqm.tree.from.SqmRoot;
|
||||
import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelection;
|
||||
|
||||
import org.hibernate.testing.orm.domain.gambit.EntityOfBasics;
|
||||
import org.hibernate.testing.orm.domain.gambit.EntityOfLists;
|
||||
import org.hibernate.testing.orm.domain.gambit.EntityOfMaps;
|
||||
import org.hibernate.testing.orm.domain.gambit.EntityOfSets;
|
||||
import org.hibernate.testing.orm.junit.TestingUtil;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.endsWith;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.sameInstance;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* Test various forms of selections
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public class SelectClauseTests extends BaseSqmUnitTest {
|
||||
|
||||
@Test
|
||||
public void testSimpleAliasSelection() {
|
||||
SqmSelectStatement statement = interpretSelect( "select p from Person p" );
|
||||
assertEquals( 1, statement.getQuerySpec().getSelectClause().getSelections().size() );
|
||||
SqmSelection selection = statement.getQuerySpec().getSelectClause().getSelections().get( 0 );
|
||||
assertThat( selection.getSelectableNode(), instanceOf( SqmRoot.class ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleAttributeSelection() {
|
||||
SqmSelectStatement statement = interpretSelect( "select p.nickName from Person p" );
|
||||
assertEquals( 1, statement.getQuerySpec().getSelectClause().getSelections().size() );
|
||||
SqmSelection selection = statement.getQuerySpec().getSelectClause().getSelections().get( 0 );
|
||||
assertThat( selection.getSelectableNode(), instanceOf( SqmSimplePath.class ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompoundAttributeSelection() {
|
||||
SqmSelectStatement statement = interpretSelect( "select p.nickName, p.name.first from Person p" );
|
||||
assertEquals( 2, statement.getQuerySpec().getSelectClause().getSelections().size() );
|
||||
assertThat(
|
||||
statement.getQuerySpec().getSelectClause().getSelections().get( 0 ).getSelectableNode(),
|
||||
instanceOf( SqmSimplePath.class )
|
||||
);
|
||||
assertThat(
|
||||
statement.getQuerySpec().getSelectClause().getSelections().get( 1 ).getSelectableNode(),
|
||||
instanceOf( SqmSimplePath.class )
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMixedAliasAndAttributeSelection() {
|
||||
SqmSelectStatement statement = interpretSelect( "select p, p.nickName from Person p" );
|
||||
assertEquals( 2, statement.getQuerySpec().getSelectClause().getSelections().size() );
|
||||
assertThat(
|
||||
statement.getQuerySpec().getSelectClause().getSelections().get( 0 ).getSelectableNode(),
|
||||
instanceOf( SqmRoot.class )
|
||||
);
|
||||
assertThat(
|
||||
statement.getQuerySpec().getSelectClause().getSelections().get( 1 ).getSelectableNode(),
|
||||
instanceOf( SqmSimplePath.class )
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinaryArithmeticExpression() {
|
||||
final String query = "select p.numberOfToes + p.numberOfToes as b from Person p";
|
||||
final SqmSelectStatement selectStatement = interpretSelect( query );
|
||||
|
||||
final SqmQuerySpec querySpec = selectStatement.getQuerySpec();
|
||||
final SqmSelection selection = querySpec.getSelectClause().getSelections().get( 0 );
|
||||
|
||||
assertThat( querySpec.getFromClause().getRoots().size(), is(1) );
|
||||
final SqmRoot root = querySpec.getFromClause().getRoots().get( 0 );
|
||||
assertThat( root.getEntityName(), endsWith( "Person" ) );
|
||||
assertThat( root.getJoins().size(), is(0) );
|
||||
|
||||
SqmBinaryArithmetic expression = (SqmBinaryArithmetic) selection.getSelectableNode();
|
||||
SqmPath leftHandOperand = (SqmPath) expression.getLeftHandOperand();
|
||||
assertThat( leftHandOperand.getLhs(), sameInstance( root ) );
|
||||
assertThat( leftHandOperand.getReferencedPathSource().getPathName(), is( "numberOfToes" ) );
|
||||
// assertThat( leftHandOperand.getFromElement(), nullValue() );
|
||||
|
||||
SqmPath rightHandOperand = (SqmPath) expression.getRightHandOperand();
|
||||
assertThat( rightHandOperand.getLhs(), sameInstance( root ) );
|
||||
assertThat( rightHandOperand.getReferencedPathSource().getPathName(), is( "numberOfToes" ) );
|
||||
// assertThat( leftHandOperand.getFromElement(), nullValue() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinaryArithmeticExpressionWithMultipleFromSpaces() {
|
||||
final String query = "select p.numberOfToes + p2.numberOfToes as b from Person p, Person p2";
|
||||
final SqmSelectStatement selectStatement = interpretSelect( query );
|
||||
|
||||
final SqmQuerySpec querySpec = selectStatement.getQuerySpec();
|
||||
final SqmSelection selection = querySpec.getSelectClause().getSelections().get( 0 );
|
||||
|
||||
assertThat( querySpec.getFromClause().getRoots().size(), is(2) );
|
||||
|
||||
final SqmRoot entityRoot = querySpec.getFromClause().getRoots().get( 0 );
|
||||
assertThat( entityRoot.getEntityName(), endsWith( "Person" ) );
|
||||
|
||||
final SqmRoot entity2Root = querySpec.getFromClause().getRoots().get( 1 );
|
||||
assertThat( entity2Root.getEntityName(), endsWith( "Person" ) );
|
||||
|
||||
SqmBinaryArithmetic addExpression = (SqmBinaryArithmetic) selection.getSelectableNode();
|
||||
|
||||
SqmPath leftHandOperand = (SqmPath) addExpression.getLeftHandOperand();
|
||||
assertThat( leftHandOperand.getLhs(), sameInstance( entityRoot ) );
|
||||
assertThat( leftHandOperand.getReferencedPathSource().getPathName(), is( "numberOfToes" ) );
|
||||
|
||||
SqmPath rightHandOperand = (SqmPath) addExpression.getRightHandOperand();
|
||||
assertThat( rightHandOperand.getLhs(), sameInstance( entity2Root ) );
|
||||
assertThat( rightHandOperand.getReferencedPathSource().getPathName(), is( "numberOfToes" ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapKeyFunction() {
|
||||
collectionIndexFunctionAssertions(
|
||||
interpretSelect( "select key(m) from EntityOfMaps e join e.basicToBasicMap m" ),
|
||||
CollectionClassification.MAP,
|
||||
BasicDomainType.class,
|
||||
"m"
|
||||
);
|
||||
collectionIndexFunctionAssertions(
|
||||
interpretSelect( "select key(m) from EntityOfMaps e join e.componentToBasicMap m" ),
|
||||
CollectionClassification.MAP,
|
||||
EmbeddableDomainType.class,
|
||||
"m"
|
||||
);
|
||||
}
|
||||
|
||||
private void collectionIndexFunctionAssertions(
|
||||
SqmSelectStatement statement,
|
||||
CollectionClassification expectedCollectionClassification,
|
||||
Class<? extends SimpleDomainType> expectedIndexDomainTypeType,
|
||||
String expectedAlias) {
|
||||
assertEquals( 1, statement.getQuerySpec().getSelectClause().getSelections().size() );
|
||||
|
||||
final SqmSelectableNode selectedExpr = statement.getQuerySpec()
|
||||
.getSelectClause()
|
||||
.getSelections()
|
||||
.get( 0 )
|
||||
.getSelectableNode();
|
||||
|
||||
assertThat( selectedExpr, instanceOf( SqmSimplePath.class ) );
|
||||
final SqmSimplePath selectedPath = (SqmSimplePath) selectedExpr;
|
||||
|
||||
assertThat( selectedPath.getLhs().getExplicitAlias(), is( expectedAlias ) );
|
||||
|
||||
final PluralPersistentAttribute attribute = (PluralPersistentAttribute) selectedPath.getLhs().getReferencedPathSource();
|
||||
|
||||
assertThat( attribute.getCollectionClassification(), is( expectedCollectionClassification ) );
|
||||
|
||||
final SimpleDomainType<?> indexDomainType = attribute.getKeyGraphType();
|
||||
assertThat( indexDomainType, instanceOf( expectedIndexDomainTypeType ) );
|
||||
|
||||
assertThat( selectedPath.getReferencedPathSource(), sameInstance( attribute.getIndexPathSource() ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapValueFunction() {
|
||||
collectionValueFunctionAssertions(
|
||||
interpretSelect( "select value(m) from EntityOfMaps e join e.basicToBasicMap m" ),
|
||||
EntityOfMaps.class.getName() + ".basicToBasicMap",
|
||||
"m"
|
||||
);
|
||||
collectionValueFunctionAssertions(
|
||||
interpretSelect( "select value(m) from EntityOfMaps e join e.basicToComponentMap m" ),
|
||||
EntityOfMaps.class.getName() + ".basicToComponentMap",
|
||||
"m"
|
||||
);
|
||||
collectionValueFunctionAssertions(
|
||||
interpretSelect( "select value(m) from EntityOfMaps e join e.basicToOneToMany m" ),
|
||||
EntityOfMaps.class.getName() + ".basicToOneToMany",
|
||||
"m"
|
||||
);
|
||||
|
||||
// todo : ManyToMany not properly handled atm
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollectionValueFunction() {
|
||||
collectionValueFunctionAssertions(
|
||||
interpretSelect( "select value(b) from EntityOfLists e join e.listOfBasics b" ),
|
||||
EntityOfLists.class.getName() + ".listOfBasics",
|
||||
"b"
|
||||
);
|
||||
collectionValueFunctionAssertions(
|
||||
interpretSelect( "select value(b) from EntityOfLists e join e.listOfComponents b" ),
|
||||
EntityOfLists.class.getName() + ".listOfComponents",
|
||||
"b"
|
||||
);
|
||||
collectionValueFunctionAssertions(
|
||||
interpretSelect( "select value(b) from EntityOfLists e join e.listOfOneToMany b" ),
|
||||
EntityOfLists.class.getName() + ".listOfOneToMany",
|
||||
"b"
|
||||
);
|
||||
|
||||
collectionValueFunctionAssertions(
|
||||
interpretSelect( "select value(b) from EntityOfSets e join e.setOfBasics b" ),
|
||||
EntityOfSets.class.getName() + ".setOfBasics",
|
||||
"b"
|
||||
);
|
||||
collectionValueFunctionAssertions(
|
||||
interpretSelect( "select value(b) from EntityOfSets e join e.setOfComponents b" ),
|
||||
EntityOfSets.class.getName() + ".setOfComponents",
|
||||
"b"
|
||||
);
|
||||
collectionValueFunctionAssertions(
|
||||
interpretSelect( "select value(b) from EntityOfSets e join e.setOfOneToMany b" ),
|
||||
EntityOfSets.class.getName() + ".setOfOneToMany",
|
||||
"b"
|
||||
);
|
||||
|
||||
// todo : ManyToMany not properly handled atm
|
||||
}
|
||||
|
||||
private void collectionValueFunctionAssertions(
|
||||
SqmSelectStatement statement,
|
||||
String collectionRole,
|
||||
String collectionIdentificationVariable) {
|
||||
assertEquals( 1, statement.getQuerySpec().getSelectClause().getSelections().size() );
|
||||
|
||||
final SqmSelectableNode selectedExpression = statement.getQuerySpec()
|
||||
.getSelectClause()
|
||||
.getSelections()
|
||||
.get( 0 )
|
||||
.getSelectableNode();
|
||||
|
||||
assertThat( selectedExpression, instanceOf( SqmPath.class ) );
|
||||
final SqmPath selectedPath = (SqmPath) selectedExpression;
|
||||
final SqmPathSource referencedPathSource = selectedPath.getReferencedPathSource();
|
||||
|
||||
final String ownerName = StringHelper.qualifier( collectionRole );
|
||||
final String attributeName = StringHelper.unqualify( collectionRole );
|
||||
|
||||
final EntityDomainType<?> entity = sessionFactory().getJpaMetamodel().entity( ownerName );
|
||||
final PluralPersistentAttribute<?,?,?> pluralAttribute = entity.findPluralAttribute( attributeName );
|
||||
|
||||
assertThat( referencedPathSource, sameInstance( pluralAttribute.getElementPathSource() ) );
|
||||
|
||||
assertThat( selectedPath.getLhs().getExplicitAlias(), is( collectionIdentificationVariable ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapEntryFunction() {
|
||||
SqmSelectStatement statement = interpretSelect( "select entry(m) from EntityOfMaps e join e.basicToManyToMany m" );
|
||||
|
||||
assertEquals( 1, statement.getQuerySpec().getSelectClause().getSelections().size() );
|
||||
|
||||
final SqmMapEntryReference mapEntryPath = (SqmMapEntryReference) statement.getQuerySpec()
|
||||
.getSelectClause()
|
||||
.getSelections()
|
||||
.get( 0 )
|
||||
.getSelectableNode();
|
||||
|
||||
assertThat( mapEntryPath.getJavaTypeDescriptor().getJavaType(), is( equalTo( Map.Entry.class ) ) );
|
||||
|
||||
final SqmPath selectedPathLhs = mapEntryPath.getMapPath();
|
||||
assertThat( selectedPathLhs.getExplicitAlias(), is( "m" ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleRootEntitySelection() {
|
||||
SqmSelectStatement statement = interpretSelect( "select e from EntityOfBasics e" );
|
||||
|
||||
assertEquals( 1, statement.getQuerySpec().getSelectClause().getSelections().size() );
|
||||
final SqmPath sqmEntityReference = TestingUtil.cast(
|
||||
statement.getQuerySpec().getSelectClause().getSelections().get( 0 ).getSelectableNode(),
|
||||
SqmPath.class
|
||||
);
|
||||
|
||||
assertThat( sqmEntityReference.getJavaTypeDescriptor().getJavaType(), equalTo( EntityOfBasics.class ));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class[] getAnnotatedClasses() {
|
||||
return new Class[] {
|
||||
Person.class,
|
||||
EntityOfBasics.class,
|
||||
EntityOfLists.class,
|
||||
EntityOfMaps.class,
|
||||
EntityOfSets.class,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user