diff --git a/hibernate-core/src/main/java/org/hibernate/Metamodel.java b/hibernate-core/src/main/java/org/hibernate/Metamodel.java index beb4e15f14..b0fdbdcf44 100644 --- a/hibernate-core/src/main/java/org/hibernate/Metamodel.java +++ b/hibernate-core/src/main/java/org/hibernate/Metamodel.java @@ -8,10 +8,18 @@ package org.hibernate; import javax.persistence.metamodel.EntityType; +import org.hibernate.metamodel.model.domain.EntityDomainType; +import org.hibernate.metamodel.model.domain.JpaMetamodel; + /** * @author Steve Ebersole + * + * @deprecated (since 6.0) Access to JPA's type system and Hibernate's type + * system has been separated into {@link JpaMetamodel} + * and {@link org.hibernate.metamodel.spi.RuntimeModel} respectively. */ -public interface Metamodel extends javax.persistence.metamodel.Metamodel { +@Deprecated +public interface Metamodel extends JpaMetamodel { /** * Access to the SessionFactory that this Metamodel instance is bound to. * @@ -34,7 +42,7 @@ public interface Metamodel extends javax.persistence.metamodel.Metamodel { * * @return The entity descriptor */ - EntityType entity(String entityName); + EntityDomainType entity(String entityName); String getImportedClassName(String className); diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractBagSemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractBagSemantics.java new file mode 100644 index 0000000000..3e518f0c3a --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractBagSemantics.java @@ -0,0 +1,52 @@ +/* + * 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.collection.internal; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.function.Consumer; + +import org.hibernate.collection.spi.CollectionSemantics; +import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.persister.collection.CollectionPersister; + +/** + * @author Steve Ebersole + */ +public abstract class AbstractBagSemantics> implements CollectionSemantics { + @Override + @SuppressWarnings("unchecked") + public B instantiateRaw( + int anticipatedSize, + CollectionPersister collectionDescriptor) { + if ( anticipatedSize < 1 ) { + return (B) new ArrayList(); + } + else { + return (B) CollectionHelper.arrayList( anticipatedSize ); + } + } + + @Override + @SuppressWarnings("unchecked") + public Iterator getElementIterator(B rawCollection) { + if ( rawCollection == null ) { + return null; + } + + return (Iterator) rawCollection.iterator(); + } + + @Override + @SuppressWarnings("unchecked") + public void visitElements(B rawCollection, Consumer action) { + if ( rawCollection != null ) { + rawCollection.forEach( action ); + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractMapSemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractMapSemantics.java new file mode 100644 index 0000000000..a82b11832b --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractMapSemantics.java @@ -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.collection.internal; + +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +import org.hibernate.collection.spi.MapSemantics; + +/** + * @author Steve Ebersole + */ +public abstract class AbstractMapSemantics> implements MapSemantics { + @Override + public Iterator getKeyIterator(M rawMap) { + if ( rawMap == null ) { + return null; + } + + return rawMap.keySet().iterator(); + } + + @Override + @SuppressWarnings("unchecked") + public void visitKeys(M rawMap, Consumer action) { + if ( rawMap != null ) { + rawMap.keySet().forEach( action ); + } + } + + @Override + @SuppressWarnings("unchecked") + public void visitEntries(M rawMap, BiConsumer action) { + if ( rawMap != null ) { + rawMap.forEach( action ); + } + } + + + @Override + public Iterator getElementIterator(Map rawMap) { + if ( rawMap == null ) { + return Collections.emptyIterator(); + } + + return rawMap.values().iterator(); + } + + @Override + @SuppressWarnings("unchecked") + public void visitElements(M rawMap, Consumer action) { + if ( rawMap != null ) { + rawMap.values().forEach( action ); + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractSetSemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractSetSemantics.java new file mode 100644 index 0000000000..d7bcb2874d --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractSetSemantics.java @@ -0,0 +1,34 @@ +/* + * 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.collection.internal; + +import java.util.Iterator; +import java.util.Set; +import java.util.function.Consumer; + +import org.hibernate.collection.spi.CollectionSemantics; + +/** + * @author Steve Ebersole + */ +public abstract class AbstractSetSemantics> implements CollectionSemantics { + @Override + public Iterator getElementIterator(Set rawCollection) { + if ( rawCollection == null ) { + return null; + } + return rawCollection.iterator(); + } + + @Override + @SuppressWarnings("unchecked") + public void visitElements(S rawCollection, Consumer action) { + if ( rawCollection != null ) { + rawCollection.forEach( action ); + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardArraySemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardArraySemantics.java new file mode 100644 index 0000000000..873732a057 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardArraySemantics.java @@ -0,0 +1,84 @@ +/* + * 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.collection.internal; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.function.Consumer; + +import org.hibernate.collection.spi.CollectionClassification; +import org.hibernate.collection.spi.CollectionSemantics; +import org.hibernate.collection.spi.PersistentCollection; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.persister.collection.CollectionPersister; + +/** + * CollectionSemantics implementation for arrays + * + * @author Steve Ebersole + */ +public class StandardArraySemantics implements CollectionSemantics { + /** + * Singleton access + */ + public static final StandardArraySemantics INSTANCE = new StandardArraySemantics(); + + private StandardArraySemantics() { + } + + @Override + public CollectionClassification getCollectionClassification() { + return CollectionClassification.ARRAY; + } + + @Override + public Object[] instantiateRaw( + int anticipatedSize, + CollectionPersister collectionDescriptor) { +// return (Object[]) Array.newInstance( +// collectionDescriptor.getJavaTypeDescriptor().getJavaType().getComponentType(), +// anticipatedSize +// ); + throw new UnsupportedOperationException(); + } + + + @Override + public PersistentCollection instantiateWrapper( + Object key, + CollectionPersister collectionDescriptor, + SharedSessionContractImplementor session) { + return new PersistentArrayHolder( key, session, collectionDescriptor ); + } + + @Override + public PersistentCollection wrap( + Object rawCollection, + CollectionPersister collectionDescriptor, + SharedSessionContractImplementor session) { + return new PersistentArrayHolder( session, collectionDescriptor, rawCollection ); + } + + @Override + @SuppressWarnings("unchecked") + public Iterator getElementIterator(Object[] rawCollection) { + return (Iterator) Arrays.stream( rawCollection ).iterator(); + } + + @Override + @SuppressWarnings("unchecked") + public void visitElements(Object[] array, Consumer action) { + if ( array == null ) { + return; + } + + for ( Object element : array ) { + action.accept( element ); + } + + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardBagSemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardBagSemantics.java new file mode 100644 index 0000000000..0c3edc3b87 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardBagSemantics.java @@ -0,0 +1,52 @@ +/* + * 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.collection.internal; + +import java.util.Collection; + +import org.hibernate.collection.spi.CollectionClassification; +import org.hibernate.collection.spi.PersistentCollection; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.persister.collection.CollectionPersister; + +/** + * CollectionSemantics for bags + * + * @author Steve Ebersole + */ +public class StandardBagSemantics extends AbstractBagSemantics> { + /** + * Singleton access + */ + public static final StandardBagSemantics INSTANCE = new StandardBagSemantics(); + + private StandardBagSemantics() { + } + + @Override + public CollectionClassification getCollectionClassification() { + return CollectionClassification.BAG; + } + + @Override + public PersistentCollection instantiateWrapper( + Object key, + CollectionPersister collectionDescriptor, + SharedSessionContractImplementor session) { + return new PersistentBag( session, collectionDescriptor ); + } + + @Override + @SuppressWarnings("unchecked") + public PersistentCollection wrap( + Object rawCollection, + CollectionPersister collectionDescriptor, + SharedSessionContractImplementor session) { + return new PersistentBag( session, collectionDescriptor, (Collection) rawCollection ); + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardIdentifierBagSemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardIdentifierBagSemantics.java new file mode 100644 index 0000000000..56de1ad941 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardIdentifierBagSemantics.java @@ -0,0 +1,52 @@ +/* + * 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.collection.internal; + +import java.util.Collection; + +import org.hibernate.collection.spi.CollectionClassification; +import org.hibernate.collection.spi.PersistentCollection; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.persister.collection.CollectionPersister; + +/** + * CollectionSemantics implementation for id-bags + * + * @author Steve Ebersole + */ +public class StandardIdentifierBagSemantics extends AbstractBagSemantics> { + /** + * Singleton access + */ + public static final StandardIdentifierBagSemantics INSTANCE = new StandardIdentifierBagSemantics(); + + private StandardIdentifierBagSemantics() { + } + + @Override + public CollectionClassification getCollectionClassification() { + return CollectionClassification.IDBAG; + } + + @Override + @SuppressWarnings("unchecked") + public PersistentCollection instantiateWrapper( + Object key, + CollectionPersister collectionDescriptor, + SharedSessionContractImplementor session) { + return new PersistentIdentifierBag( session, collectionDescriptor, key ); + } + + @Override + @SuppressWarnings("unchecked") + public PersistentCollection wrap( + Object rawCollection, + CollectionPersister collectionDescriptor, + SharedSessionContractImplementor session) { + return new PersistentIdentifierBag( session, collectionDescriptor, (Collection) rawCollection ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardListSemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardListSemantics.java new file mode 100644 index 0000000000..79aaf4c20b --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardListSemantics.java @@ -0,0 +1,74 @@ +/* + * 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.collection.internal; + +import java.util.Iterator; +import java.util.List; +import java.util.function.Consumer; + +import org.hibernate.collection.spi.CollectionClassification; +import org.hibernate.collection.spi.CollectionSemantics; +import org.hibernate.collection.spi.PersistentCollection; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.persister.collection.CollectionPersister; + +/** + * Hibernate's standard CollectionSemantics for Lists + * + * @author Steve Ebersole + */ +public class StandardListSemantics implements CollectionSemantics { + /** + * Singleton access + */ + public static final StandardListSemantics INSTANCE = new StandardListSemantics(); + + private StandardListSemantics() { + } + + @Override + public CollectionClassification getCollectionClassification() { + return CollectionClassification.LIST; + } + + @Override + public List instantiateRaw( + int anticipatedSize, + CollectionPersister collectionDescriptor) { + return CollectionHelper.arrayList( anticipatedSize ); + } + + @Override + @SuppressWarnings("unchecked") + public Iterator getElementIterator(List rawCollection) { + return rawCollection.iterator(); + } + + @Override + @SuppressWarnings("unchecked") + public void visitElements(List rawCollection, Consumer action) { + rawCollection.forEach( action ); + } + + @Override + public PersistentCollection instantiateWrapper( + Object key, + CollectionPersister collectionDescriptor, + SharedSessionContractImplementor session) { + return new PersistentList( session, collectionDescriptor, key ); + } + + @Override + @SuppressWarnings("unchecked") + public PersistentCollection wrap( + Object rawCollection, + CollectionPersister collectionDescriptor, + SharedSessionContractImplementor session) { + return new PersistentList( session, collectionDescriptor, (List) rawCollection ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardMapSemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardMapSemantics.java new file mode 100644 index 0000000000..a95bd24f7f --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardMapSemantics.java @@ -0,0 +1,58 @@ +/* + * 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.collection.internal; + +import java.util.Map; + +import org.hibernate.collection.spi.CollectionClassification; +import org.hibernate.collection.spi.PersistentCollection; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.persister.collection.CollectionPersister; + +/** + * CollectionSemantics for maps + * + * @author Steve Ebersole + */ +public class StandardMapSemantics extends AbstractMapSemantics> { + /** + * Singleton access + */ + public static final StandardMapSemantics INSTANCE = new StandardMapSemantics(); + + private StandardMapSemantics() { + } + + @Override + public CollectionClassification getCollectionClassification() { + return CollectionClassification.MAP; + } + + @Override + public Map instantiateRaw( + int anticipatedSize, + CollectionPersister collectionDescriptor) { + return CollectionHelper.mapOfSize( anticipatedSize ); + } + + @Override + public PersistentCollection instantiateWrapper( + Object key, + CollectionPersister collectionDescriptor, + SharedSessionContractImplementor session) { + return new PersistentMap( session, collectionDescriptor, key ); + } + + @Override + public PersistentCollection wrap( + Object rawCollection, + CollectionPersister collectionDescriptor, + SharedSessionContractImplementor session) { + return new PersistentMap( session, collectionDescriptor, (Map) rawCollection ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardOrderedMapSemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardOrderedMapSemantics.java new file mode 100644 index 0000000000..ee2b8da382 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardOrderedMapSemantics.java @@ -0,0 +1,62 @@ +/* + * 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.collection.internal; + +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.hibernate.collection.spi.CollectionClassification; +import org.hibernate.collection.spi.PersistentCollection; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.metamodel.model.mapping.PersistentCollectionDescriptor; + +/** + * @author Steve Ebersole + */ +public class StandardOrderedMapSemantics extends AbstractMapSemantics> { + /** + * Singleton access + */ + public static final StandardOrderedMapSemantics INSTANCE = new StandardOrderedMapSemantics(); + + private StandardOrderedMapSemantics() { + } + + @Override + public CollectionClassification getCollectionClassification() { + return CollectionClassification.ORDERED_MAP; + } + + @Override + public LinkedHashMap instantiateRaw( + int anticipatedSize, + PersistentCollectionDescriptor collectionDescriptor) { + return anticipatedSize < 1 ? new LinkedHashMap<>() : new LinkedHashMap<>( anticipatedSize ); + } + + @Override + public PersistentCollection instantiateWrapper( + Object key, + PersistentCollectionDescriptor, E> collectionDescriptor, + SharedSessionContractImplementor session) { + return new PersistentMap<>( session, collectionDescriptor, key ); + } + + @Override + public PersistentCollection wrap( + Object rawCollection, + PersistentCollectionDescriptor, E> collectionDescriptor, + SharedSessionContractImplementor session) { + return new PersistentMap<>( session, collectionDescriptor, (Map) rawCollection ); + } + + @Override + public Iterator getElementIterator(LinkedHashMap rawCollection) { + return rawCollection.entrySet().iterator(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardOrderedSetSemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardOrderedSetSemantics.java new file mode 100644 index 0000000000..f438694f4b --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardOrderedSetSemantics.java @@ -0,0 +1,62 @@ +/* + * 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.collection.internal; + +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Set; + +import org.hibernate.collection.spi.CollectionClassification; +import org.hibernate.collection.spi.PersistentCollection; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.metamodel.model.mapping.PersistentCollectionDescriptor; + +/** + * @author Steve Ebersole + */ +public class StandardOrderedSetSemantics extends AbstractSetSemantics> { + /** + * Singleton access + */ + public static final StandardOrderedSetSemantics INSTANCE = new StandardOrderedSetSemantics(); + + private StandardOrderedSetSemantics() { + } + + @Override + public CollectionClassification getCollectionClassification() { + return CollectionClassification.ORDERED_SET; + } + + @Override + public LinkedHashSet instantiateRaw( + int anticipatedSize, + PersistentCollectionDescriptor collectionDescriptor) { + return anticipatedSize < 1 ? new LinkedHashSet() : new LinkedHashSet<>( anticipatedSize ); + } + + @Override + public PersistentCollection instantiateWrapper( + Object key, + PersistentCollectionDescriptor, E> collectionDescriptor, + SharedSessionContractImplementor session) { + return new PersistentSet( session, collectionDescriptor, key ); + } + + @Override + public PersistentCollection wrap( + Object rawCollection, + PersistentCollectionDescriptor, E> collectionDescriptor, + SharedSessionContractImplementor session) { + return new PersistentSet( session, collectionDescriptor, (Set) rawCollection ); + } + + @Override + public Iterator getElementIterator(LinkedHashSet rawCollection) { + return rawCollection.iterator(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardSetSemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardSetSemantics.java new file mode 100644 index 0000000000..e584d21b90 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardSetSemantics.java @@ -0,0 +1,59 @@ +/* + * 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.collection.internal; + +import java.util.HashSet; +import java.util.Set; + +import org.hibernate.collection.spi.CollectionClassification; +import org.hibernate.collection.spi.PersistentCollection; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.persister.collection.CollectionPersister; + +/** + * @author Steve Ebersole + */ +public class StandardSetSemantics extends AbstractSetSemantics> { + /** + * Singleton access + */ + public static final StandardSetSemantics INSTANCE = new StandardSetSemantics(); + + private StandardSetSemantics() { + } + + @Override + public CollectionClassification getCollectionClassification() { + return CollectionClassification.SET; + } + + @Override + public Set instantiateRaw( + int anticipatedSize, + CollectionPersister collectionDescriptor) { + return anticipatedSize < 1 ? new HashSet<>() : new HashSet<>( anticipatedSize ); + } + + @Override + public PersistentCollection instantiateWrapper( + Object key, + CollectionPersister collectionDescriptor, + SharedSessionContractImplementor session) { + //noinspection unchecked + return new PersistentSet( session, collectionDescriptor, key ); + } + + @Override + public PersistentCollection wrap( + Object rawCollection, + CollectionPersister collectionDescriptor, + SharedSessionContractImplementor session) { + //noinspection unchecked + return new PersistentSet( session, collectionDescriptor, (Set) rawCollection ); + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardSortedMapSemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardSortedMapSemantics.java new file mode 100644 index 0000000000..acf045cd0f --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardSortedMapSemantics.java @@ -0,0 +1,58 @@ +/* + * 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.collection.internal; + +import java.util.SortedMap; +import java.util.TreeMap; + +import org.hibernate.collection.spi.CollectionClassification; +import org.hibernate.collection.spi.PersistentCollection; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.persister.collection.CollectionPersister; + +/** + * @author Steve Ebersole + */ +public class StandardSortedMapSemantics extends AbstractMapSemantics> { + /** + * Singleton access + */ + public static final StandardSortedMapSemantics INSTANCE = new StandardSortedMapSemantics(); + + private StandardSortedMapSemantics() { + } + + @Override + public CollectionClassification getCollectionClassification() { + return CollectionClassification.SORTED_MAP; + } + + @Override + public TreeMap instantiateRaw( + int anticipatedSize, + CollectionPersister collectionDescriptor) { + return new TreeMap<>( collectionDescriptor.getSortingComparator() ); + } + + @Override + @SuppressWarnings("unchecked") + public PersistentCollection instantiateWrapper( + Object key, + CollectionPersister collectionDescriptor, + SharedSessionContractImplementor session) { + return new PersistentSortedMap( session, collectionDescriptor, key ); + } + + @Override + @SuppressWarnings("unchecked") + public PersistentCollection wrap( + Object rawCollection, + CollectionPersister collectionDescriptor, + SharedSessionContractImplementor session) { + return new PersistentSortedMap( session, collectionDescriptor, (SortedMap) rawCollection ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardSortedSetSemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardSortedSetSemantics.java new file mode 100644 index 0000000000..a9cb8508ac --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardSortedSetSemantics.java @@ -0,0 +1,65 @@ +/* + * 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.collection.internal; + +import java.util.Iterator; +import java.util.SortedSet; +import java.util.TreeSet; + +import org.hibernate.collection.spi.CollectionClassification; +import org.hibernate.collection.spi.PersistentCollection; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.persister.collection.CollectionPersister; + +/** + * @author Steve Ebersole + */ +public class StandardSortedSetSemantics extends AbstractSetSemantics> { + /** + * Singleton access + */ + public static final StandardSortedSetSemantics INSTANCE = new StandardSortedSetSemantics(); + + private StandardSortedSetSemantics() { + } + + @Override + public CollectionClassification getCollectionClassification() { + return CollectionClassification.SORTED_SET; + } + + @Override + public SortedSet instantiateRaw( + int anticipatedSize, + CollectionPersister collectionDescriptor) { + return new TreeSet<>( collectionDescriptor.getSortingComparator() ); + } + + @Override + @SuppressWarnings("unchecked") + public PersistentCollection instantiateWrapper( + Object key, + CollectionPersister collectionDescriptor, + SharedSessionContractImplementor session) { + return new PersistentSortedSet( session, collectionDescriptor, key ); + } + + @Override + @SuppressWarnings("unchecked") + public PersistentCollection wrap( + Object rawCollection, + CollectionPersister collectionDescriptor, + SharedSessionContractImplementor session) { + return new PersistentSortedSet( session, collectionDescriptor, (SortedSet) rawCollection ); + } + + @Override + @SuppressWarnings("unchecked") + public Iterator getElementIterator(SortedSet rawCollection) { + return (Iterator) rawCollection.iterator(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/collection/spi/CollectionSemanticsResolver.java b/hibernate-core/src/main/java/org/hibernate/collection/spi/CollectionSemanticsResolver.java new file mode 100644 index 0000000000..69913b3354 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/collection/spi/CollectionSemanticsResolver.java @@ -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.collection.spi; + +import org.hibernate.mapping.Collection; + +/** + * todo (6.0) ... + * + * Ideally would act as the contract that allows pluggable resolution of + * non-Java Collection types - maybe as part of a generalized reflection + * on the attribute to determine its nature/classification + * + * @author Steve Ebersole + */ +public interface CollectionSemanticsResolver { + // really need some form of access to the attribute site + CollectionSemantics resolveRepresentation(Collection bootDescriptor); +} diff --git a/hibernate-core/src/main/java/org/hibernate/collection/spi/MapSemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/spi/MapSemantics.java new file mode 100644 index 0000000000..43b8ece7a7 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/collection/spi/MapSemantics.java @@ -0,0 +1,24 @@ +/* + * 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.collection.spi; + +import java.util.Iterator; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +/** + * Extension of CollectionSemantics for Maps + * + * @author Steve Ebersole + */ +public interface MapSemantics extends CollectionSemantics { + Iterator getKeyIterator(M rawMap); + + void visitKeys(M rawMap, Consumer action); + + void visitEntries(M rawMap, BiConsumer action); +} diff --git a/hibernate-core/src/main/java/org/hibernate/graph/Graph.java b/hibernate-core/src/main/java/org/hibernate/graph/Graph.java index b6ccf8c73f..80691d40d4 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/Graph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/Graph.java @@ -12,7 +12,7 @@ import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.PersistentAttribute; /** - * A container for {@link AttributeNode}s. + * A container for {@link AttributeNode} references. * * Acts as a "bridge" between JPA's {@link javax.persistence.EntityGraph} and {@link javax.persistence.Subgraph} * diff --git a/hibernate-core/src/main/java/org/hibernate/graph/RootGraph.java b/hibernate-core/src/main/java/org/hibernate/graph/RootGraph.java index 98f3da4212..a28bf57359 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/RootGraph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/RootGraph.java @@ -12,6 +12,8 @@ import javax.persistence.EntityGraph; import javax.persistence.Subgraph; import javax.persistence.metamodel.Attribute; +import org.hibernate.metamodel.model.domain.PersistentAttribute; + /** * Hibernate extension to the JPA {@link EntityGraph} contract. * @@ -24,7 +26,7 @@ public interface RootGraph extends Graph, EntityGraph { boolean appliesTo(String entityName); - boolean appliesTo(Class entityType); + boolean appliesTo(Class entityType); @Override RootGraph makeRootGraph(String name, boolean mutable); @@ -59,18 +61,20 @@ public interface RootGraph extends Graph, EntityGraph { } for ( Attribute attribute : attributes ) { - addAttributeNode( attribute ); + addAttributeNode( (PersistentAttribute) attribute ); } } @Override default SubGraph addSubgraph(Attribute attribute) { - return addSubGraph( attribute ); + //noinspection unchecked + return addSubGraph( (PersistentAttribute) attribute ); } @Override default SubGraph addSubgraph(Attribute attribute, Class type) { - return addSubGraph( attribute, type ); + //noinspection unchecked + return addSubGraph( (PersistentAttribute) attribute, type ); } @Override @@ -85,12 +89,14 @@ public interface RootGraph extends Graph, EntityGraph { @Override default SubGraph addKeySubgraph(Attribute attribute) { - return addKeySubGraph( attribute ); + //noinspection unchecked + return addKeySubGraph( (PersistentAttribute) attribute ); } @Override default SubGraph addKeySubgraph(Attribute attribute, Class type) { - return addKeySubGraph( attribute, type ); + //noinspection unchecked + return addKeySubGraph( (PersistentAttribute) attribute, type ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java index f26753f6b2..32d192adef 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraph.java @@ -12,7 +12,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.graph.AttributeNode; import org.hibernate.graph.CannotBecomeEntityGraphException; import org.hibernate.graph.CannotContainSubGraphException; @@ -23,6 +22,7 @@ import org.hibernate.graph.spi.GraphImplementor; import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.metamodel.model.domain.EntityDomainType; +import org.hibernate.metamodel.model.domain.JpaMetamodel; import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.PersistentAttribute; @@ -39,14 +39,14 @@ public abstract class AbstractGraph extends AbstractGraphNode implements G public AbstractGraph( ManagedDomainType managedType, boolean mutable, - SessionFactoryImplementor sessionFactory) { - super( mutable, sessionFactory ); + JpaMetamodel jpaMetamodel) { + super( mutable, jpaMetamodel ); this.managedType = managedType; } @SuppressWarnings("WeakerAccess") protected AbstractGraph(boolean mutable, GraphImplementor original) { - this( original.getGraphedType(), mutable, original.sessionFactory() ); + this( original.getGraphedType(), mutable, original.jpaMetamodel() ); this.attrNodeMap = CollectionHelper.concurrentMap( original.getAttributeNodeList().size() ); original.visitAttributeNodes( @@ -58,8 +58,8 @@ public abstract class AbstractGraph extends AbstractGraphNode implements G } @Override - public SessionFactoryImplementor sessionFactory() { - return super.sessionFactory(); + public JpaMetamodel jpaMetamodel() { + return super.jpaMetamodel(); } @Override @@ -196,7 +196,7 @@ public abstract class AbstractGraph extends AbstractGraphNode implements G } if ( attrNode == null ) { - attrNode = new AttributeNodeImpl<>( isMutable(), attribute, sessionFactory() ); + attrNode = new AttributeNodeImpl<>( isMutable(), attribute, jpaMetamodel() ); attrNodeMap.put( attribute, attrNode ); } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraphNode.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraphNode.java index 38a2e97857..8d32eb8662 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraphNode.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/AbstractGraphNode.java @@ -6,23 +6,23 @@ */ package org.hibernate.graph.internal; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.graph.spi.GraphNodeImplementor; +import org.hibernate.metamodel.model.domain.JpaMetamodel; /** * @author Steve Ebersole */ public abstract class AbstractGraphNode implements GraphNodeImplementor { - private final SessionFactoryImplementor sessionFactory; + private final JpaMetamodel jpaMetamodel; private final boolean mutable; - public AbstractGraphNode(boolean mutable, SessionFactoryImplementor sessionFactory) { - this.sessionFactory = sessionFactory; + public AbstractGraphNode(boolean mutable, JpaMetamodel jpaMetamodel) { + this.jpaMetamodel = jpaMetamodel; this.mutable = mutable; } - protected SessionFactoryImplementor sessionFactory() { - return sessionFactory; + protected JpaMetamodel jpaMetamodel() { + return jpaMetamodel; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java index 0186eba0a2..02aecd58ed 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java @@ -11,12 +11,12 @@ import java.util.HashMap; import java.util.Locale; import java.util.Map; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.graph.CannotContainSubGraphException; import org.hibernate.graph.SubGraph; import org.hibernate.graph.spi.AttributeNodeImplementor; import org.hibernate.graph.spi.SubGraphImplementor; import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.metamodel.model.domain.JpaMetamodel; import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.PersistentAttribute; import org.hibernate.metamodel.model.domain.SimpleDomainType; @@ -40,8 +40,8 @@ public class AttributeNodeImpl public AttributeNodeImpl( boolean mutable, PersistentAttribute attribute, - SessionFactoryImplementor sessionFactory) { - this( mutable, attribute, null, null, sessionFactory ); + JpaMetamodel jpaMetamodel) { + this( mutable, attribute, null, null, jpaMetamodel ); } /** @@ -52,8 +52,8 @@ public class AttributeNodeImpl PersistentAttribute attribute, Map, SubGraphImplementor> subGraphMap, Map, SubGraphImplementor> keySubGraphMap, - SessionFactoryImplementor sessionFactory) { - super( mutable, sessionFactory ); + JpaMetamodel jpaMetamodel) { + super( mutable, jpaMetamodel ); this.attribute = attribute; this.subGraphMap = subGraphMap; this.keySubGraphMap = keySubGraphMap; @@ -152,7 +152,7 @@ public class AttributeNodeImpl @SuppressWarnings({"WeakerAccess", "unchecked"}) protected void internalAddSubGraph(Class subType, SubGraphImplementor subGraph) { - log.tracef( "Adding sub-graph : ( (%s) %s )", subGraph.getGraphedType().getName(), getAttributeName() ); + log.tracef( "Adding sub-graph : ( (%s) %s )", subGraph.getGraphedType().getTypeName(), getAttributeName() ); if ( subGraphMap == null ) { subGraphMap = new HashMap<>(); @@ -265,7 +265,7 @@ public class AttributeNodeImpl this.attribute, makeMapCopy( mutable, (Map) subGraphMap ), makeMapCopy( mutable, (Map) keySubGraphMap ), - sessionFactory() + jpaMetamodel() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/RootGraphImpl.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/RootGraphImpl.java index adaa21e152..38905694ef 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/RootGraphImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/RootGraphImpl.java @@ -9,13 +9,13 @@ package org.hibernate.graph.internal; import javax.persistence.EntityGraph; import org.hibernate.cfg.NotYetImplementedException; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.graph.SubGraph; import org.hibernate.graph.spi.GraphImplementor; import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.graph.spi.SubGraphImplementor; import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.IdentifiableDomainType; +import org.hibernate.metamodel.model.domain.JpaMetamodel; /** * The Hibernate implementation of the JPA EntityGraph contract. @@ -29,17 +29,17 @@ public class RootGraphImpl extends AbstractGraph implements EntityGraph String name, EntityDomainType entityType, boolean mutable, - SessionFactoryImplementor sessionFactory) { - super( entityType, mutable, sessionFactory ); + JpaMetamodel jpaMetamodel) { + super( entityType, mutable, jpaMetamodel ); this.name = name; } - public RootGraphImpl(String name, EntityDomainType entityType, SessionFactoryImplementor sessionFactory) { + public RootGraphImpl(String name, EntityDomainType entityType, JpaMetamodel jpaMetamodel) { this( name, entityType, true, - sessionFactory + jpaMetamodel ); } @@ -96,11 +96,11 @@ public class RootGraphImpl extends AbstractGraph implements EntityGraph @Override public boolean appliesTo(String entityName) { - return appliesTo( sessionFactory().getMetamodel().entity( entityName ) ); + return appliesTo( jpaMetamodel().entity( entityName ) ); } @Override - public boolean appliesTo(Class entityType) { - return appliesTo( sessionFactory().getMetamodel().entity( entityType ) ); + public boolean appliesTo(Class type) { + return appliesTo( jpaMetamodel().entity( type ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/SubGraphImpl.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/SubGraphImpl.java index dbede27123..2d95155d89 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/SubGraphImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/SubGraphImpl.java @@ -6,13 +6,9 @@ */ package org.hibernate.graph.internal; -import javax.persistence.metamodel.Attribute; - -import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.graph.spi.AttributeNodeImplementor; import org.hibernate.graph.spi.SubGraphImplementor; +import org.hibernate.metamodel.model.domain.JpaMetamodel; import org.hibernate.metamodel.model.domain.ManagedDomainType; -import org.hibernate.metamodel.model.domain.PersistentAttribute; /** * @author Steve Ebersole @@ -21,8 +17,8 @@ public class SubGraphImpl extends AbstractGraph implements SubGraphImpleme public SubGraphImpl( ManagedDomainType managedType, boolean mutable, - SessionFactoryImplementor sessionFactory) { - super( managedType, mutable, sessionFactory ); + JpaMetamodel jpaMetamodel) { + super( managedType, mutable, jpaMetamodel ); } public SubGraphImpl(boolean mutable, AbstractGraph original) { @@ -48,12 +44,6 @@ public class SubGraphImpl extends AbstractGraph implements SubGraphImpleme return super.addKeySubGraph( attributeName ); } - @Override - @SuppressWarnings("unchecked") - public AttributeNodeImplementor addAttributeNode(Attribute attribute) { - return addAttributeNode( (PersistentAttribute) attribute ); - } - @Override public boolean appliesTo(ManagedDomainType managedType) { if ( this.getGraphedType().equals( managedType ) ) { @@ -73,6 +63,6 @@ public class SubGraphImpl extends AbstractGraph implements SubGraphImpleme @Override public boolean appliesTo(Class javaType) { - return appliesTo( sessionFactory().getMetamodel().managedType( javaType ) ); + return appliesTo( jpaMetamodel().managedType( javaType ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java b/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java index e41990b411..917da3a2c5 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/spi/GraphImplementor.java @@ -9,11 +9,11 @@ package org.hibernate.graph.spi; import java.util.List; import java.util.function.Consumer; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.graph.AttributeNode; import org.hibernate.graph.CannotBecomeEntityGraphException; import org.hibernate.graph.CannotContainSubGraphException; import org.hibernate.graph.Graph; +import org.hibernate.metamodel.model.domain.JpaMetamodel; import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.PersistentAttribute; @@ -32,7 +32,7 @@ public interface GraphImplementor extends Graph, GraphNodeImplementor { @SuppressWarnings("unchecked") void merge(GraphImplementor... others); - SessionFactoryImplementor sessionFactory(); + JpaMetamodel jpaMetamodel(); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java index f4e6b3bdc7..199bfa53ca 100755 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java @@ -20,10 +20,12 @@ import javax.persistence.metamodel.PluralAttribute; import javax.persistence.metamodel.Type; import org.hibernate.annotations.common.AssertionFailure; +import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.internal.EntityManagerMessageLogger; import org.hibernate.internal.HEMLogging; import org.hibernate.mapping.Collection; import org.hibernate.mapping.Component; +import org.hibernate.mapping.List; import org.hibernate.mapping.Map; import org.hibernate.mapping.OneToMany; import org.hibernate.mapping.PersistentClass; @@ -46,10 +48,10 @@ import org.hibernate.metamodel.model.domain.internal.SingularAttributeImpl; import org.hibernate.property.access.internal.PropertyAccessMapImpl; import org.hibernate.property.access.spi.Getter; import org.hibernate.tuple.entity.EntityMetamodel; -import org.hibernate.type.ComponentType; import org.hibernate.type.EmbeddedComponentType; import org.hibernate.type.EntityType; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry; /** * A factory for building {@link Attribute} instances. Exposes 3 main services for building
    @@ -233,23 +235,50 @@ public class AttributeFactory { } case EMBEDDABLE: { final Component component = (Component) typeContext.getHibernateValue(); + final EmbeddableTypeImpl embeddableType; - Class javaType; - if ( component.getComponentClassName() == null ) { - javaType = typeContext.getJpaBindableType(); + if ( component.getComponentClass() != null + || component.getComponentClassName() != null ) { + // we should have a non-dynamic embeddable + + final Class embeddableClass; + if ( component.getComponentClass() != null ) { + embeddableClass = component.getComponentClass(); + } + else { + embeddableClass = context.getSessionFactory() + .getServiceRegistry() + .getService( ClassLoaderService.class ) + .classForName( component.getComponentClassName() ); + } + + final EmbeddableDomainType cached = context.locateEmbeddable( embeddableClass ); + if ( cached != null ) { + return cached; + } + + final JavaTypeDescriptorRegistry registry = context.getSessionFactory() + .getMetamodel() + .getTypeConfiguration() + .getJavaTypeDescriptorRegistry(); + final JavaTypeDescriptor javaTypeDescriptor = registry.resolveDescriptor( embeddableClass ); + + embeddableType = new EmbeddableTypeImpl( + javaTypeDescriptor, + context.getSessionFactory().getQueryEngine().getCriteriaBuilder() + ); + + context.registerEmbeddableType( embeddableType ); + + return embeddableType; } else { - javaType = component.getComponentClass(); + embeddableType = new EmbeddableTypeImpl( + component.getRoleName(), + context.getSessionFactory().getQueryEngine().getCriteriaBuilder() + ); } - final EmbeddableTypeImpl embeddableType = new EmbeddableTypeImpl( - javaType, - typeContext.getAttributeMetadata().getOwnerType(), - (ComponentType) typeContext.getHibernateValue().getType(), - context.getSessionFactory().getQueryEngine().getCriteriaBuilder() - ); - context.registerEmbeddableType( embeddableType ); - final EmbeddableTypeImpl.InFlightAccess inFlightAccess = embeddableType.getInFlightAccess(); final Iterator subProperties = component.getPropertyIterator(); while ( subProperties.hasNext() ) { @@ -548,6 +577,9 @@ public class AttributeFactory { indexClassification = AttributeClassification.BASIC; } } + else if ( value instanceof List ) { + indexClassification = AttributeClassification.BASIC; + } else { indexClassification = null; } @@ -780,7 +812,7 @@ public class AttributeFactory { implements PluralAttributeMetadata { private final PluralAttribute.CollectionType attributeCollectionType; private final AttributeClassification elementClassification; - private final AttributeClassification keyClassification; + private final AttributeClassification listIndexOrMapKeyClassification; private final Class elementJavaType; private final Class keyJavaType; private final ValueContext elementValueContext; @@ -792,14 +824,14 @@ public class AttributeFactory { Member member, AttributeClassification attributeClassification, AttributeClassification elementClassification, - AttributeClassification keyClassification) { + AttributeClassification listIndexOrMapKeyClassification) { super( propertyMapping, ownerType, member, attributeClassification ); this.attributeCollectionType = determineCollectionType( getJavaType() ); this.elementClassification = elementClassification; - this.keyClassification = keyClassification; + this.listIndexOrMapKeyClassification = listIndexOrMapKeyClassification; ParameterizedType signatureType = getSignatureType( member ); - if ( this.keyClassification == null ) { + if ( this.listIndexOrMapKeyClassification == null ) { elementJavaType = signatureType != null ? getClassFromGenericArgument( signatureType.getActualTypeArguments()[0] ) : Object.class; //FIXME and honor targetEntity? @@ -843,7 +875,7 @@ public class AttributeFactory { }; // interpret the key, if one - if ( this.keyClassification != null ) { + if ( this.listIndexOrMapKeyClassification != null ) { this.keyValueContext = new ValueContext() { public Value getHibernateValue() { return ( (Map) getPropertyMapping().getValue() ).getIndex(); @@ -854,7 +886,7 @@ public class AttributeFactory { } public ValueClassification getValueClassification() { - switch ( PluralAttributeMetadataImpl.this.keyClassification ) { + switch ( PluralAttributeMetadataImpl.this.listIndexOrMapKeyClassification ) { case EMBEDDED: { return ValueClassification.EMBEDDABLE; } @@ -968,6 +1000,8 @@ public class AttributeFactory { final EmbeddableDomainType embeddableType = (EmbeddableDomainType) attributeContext.getOwnerType(); final String attributeName = attributeContext.getPropertyMapping().getName(); + final Component component = (Component) attributeContext.getPropertyMapping().getValue(); + final Getter getter = embeddableType.getHibernateType() .getComponentTuplizer() .getGetter( embeddableType.getHibernateType().getPropertyIndex( attributeName ) ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java index 0109570ca9..36cb90c9bb 100755 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java @@ -45,7 +45,6 @@ import org.hibernate.metamodel.model.domain.internal.AttributeContainer; import org.hibernate.metamodel.model.domain.internal.BasicTypeImpl; import org.hibernate.metamodel.model.domain.internal.EntityTypeImpl; import org.hibernate.metamodel.model.domain.internal.MappedSuperclassTypeImpl; -import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry; /** @@ -73,7 +72,7 @@ class MetadataContext { private Map> entityTypesByEntityName = new HashMap<>(); private Map> entityTypesByPersistentClass = new HashMap<>(); - private Set> embeddables = new HashSet<>(); + private Map> embeddables = new HashMap<>(); private Map> mappedSuperclassByMappedSuperclassMapping = new HashMap<>(); private Map, PersistentClass> mappedSuperClassTypeToPersistentClass = new HashMap<>(); @@ -113,7 +112,7 @@ class MetadataContext { } public Set> getEmbeddableTypeSet() { - return Collections.unmodifiableSet( embeddables ); + return new HashSet<>( embeddables.values() ); } public Map, MappedSuperclassType> getMappedSuperclassTypeMap() { @@ -147,9 +146,10 @@ class MetadataContext { } /*package*/ void registerEmbeddableType(EmbeddableDomainType embeddableType) { - if ( !( ignoreUnsupported && Map.class.isAssignableFrom( embeddableType.getExpressableJavaTypeDescriptor().getJavaType() ) ) ) { - embeddables.add( embeddableType ); - } + assert embeddableType.getJavaType() != null; + assert ! Map.class.isAssignableFrom( embeddableType.getJavaType() ); + + embeddables.put( embeddableType.getJavaType(), embeddableType ); } /*package*/ void registerMappedSuperclassType( @@ -170,6 +170,7 @@ class MetadataContext { * * @return Tne corresponding JPA {@link org.hibernate.type.EntityType}, or null if not yet processed. */ + @SuppressWarnings("WeakerAccess") public EntityDomainType locateEntityType(PersistentClass persistentClass) { return entityTypesByPersistentClass.get( persistentClass ); } @@ -194,16 +195,17 @@ class MetadataContext { * * @return The corresponding JPA {@link org.hibernate.type.EntityType}, or null. */ - @SuppressWarnings({"unchecked"}) + @SuppressWarnings({"unchecked", "WeakerAccess"}) public EntityDomainType locateEntityType(String entityName) { return (EntityDomainType) entityTypesByEntityName.get( entityName ); } + @SuppressWarnings("WeakerAccess") public Map> getEntityTypesByEntityName() { return Collections.unmodifiableMap( entityTypesByEntityName ); } - @SuppressWarnings({"unchecked"}) + @SuppressWarnings({"unchecked", "WeakerAccess"}) public void wrapUp() { if ( LOG.isTraceEnabled() ) { LOG.trace( "Wrapping up metadata context..." ); @@ -215,7 +217,6 @@ class MetadataContext { //we need to process types from superclasses to subclasses for ( Object mapping : orderedMappings ) { if ( PersistentClass.class.isAssignableFrom( mapping.getClass() ) ) { - @SuppressWarnings("unchecked") final PersistentClass safeMapping = (PersistentClass) mapping; if ( LOG.isTraceEnabled() ) { LOG.trace( "Starting entity [" + safeMapping.getEntityName() + ']' ); @@ -258,7 +259,6 @@ class MetadataContext { } } else if ( MappedSuperclass.class.isAssignableFrom( mapping.getClass() ) ) { - @SuppressWarnings("unchecked") final MappedSuperclass safeMapping = (MappedSuperclass) mapping; if ( LOG.isTraceEnabled() ) { LOG.trace( "Starting mapped superclass [" + safeMapping.getMappedClass().getName() + ']' ); @@ -299,7 +299,7 @@ class MetadataContext { } if ( staticMetamodelScanEnabled ) { - for ( EmbeddableDomainType embeddable : embeddables ) { + for ( EmbeddableDomainType embeddable : embeddables.values() ) { populateStaticMetamodel( embeddable ); } } @@ -307,7 +307,7 @@ class MetadataContext { @SuppressWarnings("unchecked") - private void applyIdMetadata(PersistentClass persistentClass, IdentifiableDomainType identifiableType) { + private void applyIdMetadata(PersistentClass persistentClass, IdentifiableDomainType identifiableType) { if ( persistentClass.hasIdentifierProperty() ) { final Property declaredIdentifierProperty = persistentClass.getDeclaredIdentifierProperty(); if ( declaredIdentifierProperty != null ) { @@ -551,13 +551,14 @@ class MetadataContext { } public Set getUnusedMappedSuperclasses() { - return new HashSet( knownMappedSuperclasses ); + return new HashSet<>( knownMappedSuperclasses ); } private final Map,BasicDomainType> basicDomainTypeMap = new HashMap<>(); public BasicDomainType resolveBasicType(Class javaType) { - return basicDomainTypeMap.computeIfAbsent( + //noinspection unchecked + return (BasicDomainType) basicDomainTypeMap.computeIfAbsent( javaType, jt -> { final JavaTypeDescriptorRegistry registry = getSessionFactory() @@ -566,6 +567,11 @@ class MetadataContext { .getJavaTypeDescriptorRegistry(); return new BasicTypeImpl<>( registry.resolveDescriptor( javaType ) ); } - ) + ); + } + + public EmbeddableDomainType locateEmbeddable(Class embeddableClass) { + //noinspection unchecked + return (EmbeddableDomainType) embeddables.get( embeddableClass ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractDomainType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractDomainType.java index 09f661768d..ab51963038 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractDomainType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractDomainType.java @@ -6,27 +6,26 @@ */ package org.hibernate.metamodel.model.domain; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** * @author Steve Ebersole */ -public abstract class AbstractDomainType implements DomainType { - private final SessionFactoryImplementor sessionFactory; +public abstract class AbstractDomainType implements SimpleDomainType { + private final JpaMetamodel jpaMetamodel; private final JavaTypeDescriptor javaTypeDescriptor; @SuppressWarnings("WeakerAccess") public AbstractDomainType( JavaTypeDescriptor javaTypeDescriptor, - SessionFactoryImplementor sessionFactory) { + JpaMetamodel jpaMetamodel) { this.javaTypeDescriptor = javaTypeDescriptor; - this.sessionFactory = sessionFactory; + this.jpaMetamodel = jpaMetamodel; } - protected SessionFactoryImplementor sessionFactory() { - return sessionFactory; + protected JpaMetamodel jpaMetamodel() { + return jpaMetamodel; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractIdentifiableType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractIdentifiableType.java index f41d91ee45..9ec808e8d3 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractIdentifiableType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractIdentifiableType.java @@ -13,8 +13,6 @@ import java.util.function.Consumer; import javax.persistence.metamodel.IdentifiableType; import javax.persistence.metamodel.SingularAttribute; -import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.metamodel.RepresentationMode; import org.hibernate.metamodel.model.domain.internal.AttributeContainer; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; @@ -48,8 +46,8 @@ public abstract class AbstractIdentifiableType boolean hasIdClass, boolean hasIdentifierProperty, boolean versioned, - SessionFactoryImplementor sessionFactory) { - super( typeName, javaTypeDescriptor, superType, sessionFactory ); + JpaMetamodel jpaMetamodel) { + super( typeName, javaTypeDescriptor, superType, jpaMetamodel ); this.hasIdClass = hasIdClass; this.hasIdentifierProperty = hasIdentifierProperty; this.isVersioned = versioned; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractManagedType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractManagedType.java index 4fef4d5031..cfdce44c79 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractManagedType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractManagedType.java @@ -12,6 +12,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.function.Consumer; import javax.persistence.metamodel.Attribute; import javax.persistence.metamodel.CollectionAttribute; import javax.persistence.metamodel.ListAttribute; @@ -21,7 +22,6 @@ import javax.persistence.metamodel.PluralAttribute; import javax.persistence.metamodel.SetAttribute; import javax.persistence.metamodel.SingularAttribute; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.graph.internal.SubGraphImpl; import org.hibernate.graph.spi.SubGraphImplementor; import org.hibernate.metamodel.RepresentationMode; @@ -49,8 +49,8 @@ public abstract class AbstractManagedType String hibernateTypeName, JavaTypeDescriptor javaTypeDescriptor, ManagedDomainType superType, - SessionFactoryImplementor sessionFactory) { - super( javaTypeDescriptor, sessionFactory ); + JpaMetamodel jpaMetamodel) { + super( javaTypeDescriptor, jpaMetamodel ); this.hibernateTypeName = hibernateTypeName; this.superType = superType; @@ -74,6 +74,20 @@ public abstract class AbstractManagedType return representationMode; } + @Override + @SuppressWarnings("unchecked") + public void visitAttributes(Consumer> action) { + visitDeclaredAttributes( (Consumer) action ); + if ( getSuperType() != null ) { + getSuperType().visitAttributes( (Consumer) action ); + } + } + + @Override + public void visitDeclaredAttributes(Consumer> action) { + declaredSingularAttributes.values().forEach( action ); + declaredPluralAttributes.values().forEach( action ); + } @Override @SuppressWarnings("unchecked") @@ -555,17 +569,17 @@ public abstract class AbstractManagedType @SuppressWarnings("unchecked") @Override public SubGraphImplementor makeSubGraph() { - return new SubGraphImpl( this, true, sessionFactory() ); + return new SubGraphImpl( this, true, jpaMetamodel() ); } @Override public ManagedDomainType findSubType(String subTypeName) { - return DomainModelHelper.resolveSubType( this, subTypeName, sessionFactory() ); + return DomainModelHelper.resolveSubType( this, subTypeName, jpaMetamodel() ); } @Override public ManagedDomainType findSubType(Class subType) { - return DomainModelHelper.resolveSubType( this, subType, sessionFactory() ); + return DomainModelHelper.resolveSubType( this, subType, jpaMetamodel() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/JpaMetamodel.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/JpaMetamodel.java new file mode 100644 index 0000000000..37f2760fe5 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/JpaMetamodel.java @@ -0,0 +1,86 @@ +/* + * 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.model.domain; + +import java.util.Set; +import java.util.function.Consumer; +import javax.persistence.metamodel.EmbeddableType; +import javax.persistence.metamodel.EntityType; +import javax.persistence.metamodel.ManagedType; + +import org.hibernate.service.ServiceRegistry; +import org.hibernate.type.spi.TypeConfiguration; + +/** + * Hibernate extension to the JPA {@link javax.persistence.metamodel.Metamodel} contract + * + * @see org.hibernate.metamodel.spi.RuntimeModel + * + * @author Steve Ebersole + */ +public interface JpaMetamodel extends javax.persistence.metamodel.Metamodel { + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Context + + /** + * todo (6.0) : should we expose JpaMetamodel from TypeConfiguration? + */ + TypeConfiguration getTypeConfiguration(); + + default ServiceRegistry getServiceRegistry() { + return getTypeConfiguration().getServiceRegistry(); + } + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Extended features + + /** + * Access to an entity supporting Hibernate's entity-name feature + */ + EntityDomainType entity(String entityName); + + /** + * Specialized handling for resolving entity-name references in + * an HQL query + */ + EntityDomainType resolveHqlEntityReference(String entityName); + + void visitManagedTypes(Consumer> action); + + void visitEntityTypes(Consumer> action); + void visitRootEntityTypes(Consumer> action); + + void visitEmbeddables(Consumer> action); + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Covariant returns + + @Override + ManagedDomainType managedType(Class cls); + + @Override + EntityDomainType entity(Class cls); + + @Override + EmbeddableDomainType embeddable(Class cls); + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // JPA defined bulk accessors + + @Override + Set> getManagedTypes(); + + @Override + Set> getEntities(); + + @Override + Set> getEmbeddables(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/ManagedDomainType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/ManagedDomainType.java index ee146f13c9..ed797dd7a2 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/ManagedDomainType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/ManagedDomainType.java @@ -21,25 +21,24 @@ public interface ManagedDomainType extends SimpleDomainType, ManagedType getSuperType(); - RepresentationMode getRepresentationMode(); - void visitAttributes(Consumer> action); void visitDeclaredAttributes(Consumer> action); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractAttribute.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractAttribute.java index a98b755b2f..3a48e2046a 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractAttribute.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractAttribute.java @@ -61,11 +61,6 @@ public abstract class AbstractAttribute implements PersistentAttribute getJavaType() { return attributeType.getJavaType(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractPluralAttribute.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractPluralAttribute.java index 365862e704..4e749f1a2e 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractPluralAttribute.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractPluralAttribute.java @@ -42,9 +42,9 @@ public abstract class AbstractPluralAttribute AbstractManagedType ownerType, SimpleDomainType attrType, JavaTypeDescriptor collectionClass, - SimpleDomainType keyType, + SimpleDomainType listIndexOrMapKeyType, NodeBuilder nodeBuilder) { - return new PluralAttributeBuilder<>( ownerType, attrType, collectionClass, keyType, nodeBuilder ); + return new PluralAttributeBuilder<>( ownerType, attrType, collectionClass, listIndexOrMapKeyType, nodeBuilder ); } private final CollectionClassification classification; @@ -94,6 +94,11 @@ public abstract class AbstractPluralAttribute ); } + @Override + public String getPathName() { + return getName(); + } + @Override public CollectionClassification getCollectionClassification() { return classification; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/BagAttributeImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/BagAttributeImpl.java index 4221f23a2d..e9af92e0e5 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/BagAttributeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/BagAttributeImpl.java @@ -11,8 +11,11 @@ import java.util.Collection; import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.metamodel.model.domain.BagPersistentAttribute; import org.hibernate.query.sqm.SqmPathSource; -import org.hibernate.query.sqm.produce.path.spi.SemanticPathPart; import org.hibernate.query.sqm.produce.spi.SqmCreationState; +import org.hibernate.query.sqm.tree.SqmJoinType; +import org.hibernate.query.sqm.tree.domain.SqmBagJoin; +import org.hibernate.query.sqm.tree.from.SqmAttributeJoin; +import org.hibernate.query.sqm.tree.from.SqmFrom; /** * @author Steve Ebersole @@ -34,4 +37,22 @@ class BagAttributeImpl public SqmPathSource findSubPathSource(String name) { throw new NotYetImplementedFor6Exception(); } + + @Override + public SqmAttributeJoin createSqmJoin( + SqmFrom lhs, + SqmJoinType joinType, + String alias, + boolean fetched, + SqmCreationState creationState) { + //noinspection unchecked + return new SqmBagJoin( + lhs, + this, + alias, + joinType, + fetched, + creationState.getCreationContext().getQueryEngine().getCriteriaBuilder() + ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DomainModelHelper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DomainModelHelper.java index b00ac70e97..8025c438ea 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DomainModelHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DomainModelHelper.java @@ -16,8 +16,8 @@ import org.hibernate.metamodel.model.domain.BasicDomainType; import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.EmbeddableDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType; +import org.hibernate.metamodel.model.domain.JpaMetamodel; import org.hibernate.metamodel.model.domain.ManagedDomainType; -import org.hibernate.metamodel.spi.MetamodelImplementor; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SqmPathSource; @@ -33,32 +33,26 @@ public class DomainModelHelper { public static ManagedDomainType resolveSubType( ManagedDomainType baseType, String subTypeName, - SessionFactoryImplementor sessionFactory) { - final MetamodelImplementor metamodel = sessionFactory.getMetamodel(); - + JpaMetamodel jpaMetamodel) { if ( baseType instanceof EmbeddableDomainType ) { // todo : at least validate the string is a valid sub-type of the embeddable class? return (ManagedDomainType) baseType; } - final String importedClassName = metamodel.getImportedClassName( subTypeName ); - if ( importedClassName != null ) { - // first, try to find it by name directly.. - ManagedDomainType subManagedType = metamodel.entity( importedClassName ); - if ( subManagedType != null ) { - return subManagedType; - } + // first, try to find it by name directly.. + ManagedDomainType subManagedType = jpaMetamodel.entity( subTypeName ); + if ( subManagedType != null ) { + return subManagedType; + } - // it could still be a mapped-superclass - try { - final Class subTypeClass = sessionFactory.getServiceRegistry() - .getService( ClassLoaderService.class ) - .classForName( importedClassName ); - - return metamodel.managedType( subTypeClass ); - } - catch (Exception ignore) { - } + // it could still be a mapped-superclass + try { + final Class javaType = jpaMetamodel.getServiceRegistry() + .getService( ClassLoaderService.class ) + .classForName( subTypeName ); + return jpaMetamodel.managedType( javaType ); + } + catch (Exception ignore) { } throw new IllegalArgumentException( "Unknown sub-type name (" + baseType.getTypeName() + ") : " + subTypeName ); @@ -67,10 +61,9 @@ public class DomainModelHelper { public static ManagedDomainType resolveSubType( ManagedDomainType baseType, Class subTypeClass, - SessionFactoryImplementor sessionFactory) { + JpaMetamodel jpaMetamodel) { // todo : validate the hierarchy-ness... - final MetamodelImplementor metamodel = sessionFactory.getMetamodel(); - return metamodel.managedType( subTypeClass ); + return jpaMetamodel.managedType( subTypeClass ); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddableTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddableTypeImpl.java index a896468c49..4d497ac497 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddableTypeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddableTypeImpl.java @@ -9,13 +9,11 @@ package org.hibernate.metamodel.model.domain.internal; import java.io.Serializable; import java.util.Map; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.graph.internal.SubGraphImpl; import org.hibernate.graph.spi.SubGraphImplementor; import org.hibernate.metamodel.model.domain.AbstractManagedType; import org.hibernate.metamodel.model.domain.EmbeddableDomainType; -import org.hibernate.metamodel.model.domain.ManagedDomainType; -import org.hibernate.type.ComponentType; +import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** @@ -29,33 +27,20 @@ public class EmbeddableTypeImpl extends AbstractManagedType implements EmbeddableDomainType, Serializable { - private final ManagedDomainType parent; - private final ComponentType hibernateType; - - public EmbeddableTypeImpl( - JavaTypeDescriptor javaTypeDescriptor, - ManagedDomainType parent, - ComponentType hibernateType, - SessionFactoryImplementor sessionFactory) { - super( javaTypeDescriptor.getJavaType().getName(), javaTypeDescriptor, null, sessionFactory ); - this.parent = parent; - this.hibernateType = hibernateType; + public EmbeddableTypeImpl(JavaTypeDescriptor javaTypeDescriptor, NodeBuilder nodeBuilder) { + super( javaTypeDescriptor.getJavaType().getName(), javaTypeDescriptor, null, nodeBuilder.getDomainModel() ); } public EmbeddableTypeImpl( String name, - ManagedDomainType parent, - ComponentType hibernateType, - SessionFactoryImplementor sessionFactory) { + NodeBuilder nodeBuilder) { //noinspection unchecked super( name, - (JavaTypeDescriptor) sessionFactory.getMetamodel().getTypeConfiguration().getJavaTypeDescriptorRegistry().getDescriptor( Map.class ), + (JavaTypeDescriptor) nodeBuilder.getDomainModel().getTypeConfiguration().getJavaTypeDescriptorRegistry().getDescriptor( Map.class ), null, - sessionFactory + nodeBuilder.getDomainModel() ); - this.parent = parent; - this.hibernateType = hibernateType; } @Override @@ -63,17 +48,9 @@ public class EmbeddableTypeImpl return PersistenceType.EMBEDDABLE; } - public ManagedDomainType getParent() { - return parent; - } - - public ComponentType getHibernateType() { - return hibernateType; - } - @Override @SuppressWarnings("unchecked") public SubGraphImplementor makeSubGraph(Class subType) { - return new SubGraphImpl( this, true, sessionFactory() ); + return new SubGraphImpl( this, true, jpaMetamodel() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityTypeImpl.java index d16f75ac2a..9488bfe20b 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityTypeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityTypeImpl.java @@ -9,7 +9,6 @@ package org.hibernate.metamodel.model.domain.internal; import java.io.Serializable; import javax.persistence.metamodel.EntityType; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.graph.internal.SubGraphImpl; import org.hibernate.graph.spi.SubGraphImplementor; import org.hibernate.mapping.PersistentClass; @@ -17,8 +16,8 @@ import org.hibernate.metamodel.model.domain.AbstractIdentifiableType; import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.IdentifiableDomainType; +import org.hibernate.metamodel.model.domain.JpaMetamodel; import org.hibernate.query.sqm.SqmPathSource; -import org.hibernate.query.sqm.produce.path.spi.SemanticPathPart; import org.hibernate.query.sqm.produce.spi.SqmCreationState; import org.hibernate.query.sqm.tree.domain.SqmPath; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; @@ -34,12 +33,11 @@ public class EntityTypeImpl implements EntityDomainType, Serializable { private final String jpaEntityName; - @SuppressWarnings("unchecked") public EntityTypeImpl( JavaTypeDescriptor javaTypeDescriptor, IdentifiableDomainType superType, PersistentClass persistentClass, - SessionFactoryImplementor sessionFactory) { + JpaMetamodel jpaMetamodel) { super( persistentClass.getEntityName(), javaTypeDescriptor, @@ -47,7 +45,7 @@ public class EntityTypeImpl persistentClass.getDeclaredIdentifierMapper() != null || ( superType != null && superType.hasIdClass() ), persistentClass.hasIdentifierProperty(), persistentClass.isVersioned(), - sessionFactory + jpaMetamodel ); this.jpaEntityName = persistentClass.getJpaEntityName(); } @@ -74,16 +72,7 @@ public class EntityTypeImpl @Override public SqmPathSource findSubPathSource(String name) { - return findAttribute( name ); - } - - @Override - public SemanticPathPart resolvePathPart( - String name, - String currentContextKey, - boolean isTerminal, - SqmCreationState creationState) { - return findAttribute( name ); + return (SqmPathSource) findAttribute( name ); } @Override @@ -124,7 +113,7 @@ public class EntityTypeImpl ); } - return new SubGraphImpl( this, true, sessionFactory() ); + return new SubGraphImpl( this, true, jpaMetamodel() ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/JpaMetamodelImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/JpaMetamodelImpl.java new file mode 100644 index 0000000000..25abba6f33 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/JpaMetamodelImpl.java @@ -0,0 +1,146 @@ +/* + * 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.model.domain.internal; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; +import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; +import org.hibernate.metamodel.model.domain.EmbeddableDomainType; +import org.hibernate.metamodel.model.domain.EntityDomainType; +import org.hibernate.metamodel.model.domain.JpaMetamodel; +import org.hibernate.query.sqm.tree.domain.SqmPolymorphicRootDescriptor; +import org.hibernate.type.spi.TypeConfiguration; + +/** + * @author Steve Ebersole + */ +public class JpaMetamodelImpl implements JpaMetamodel { + private static final String INVALID_IMPORT = ""; + + private final TypeConfiguration typeConfiguration; + + private final Map> entityDescriptorMap; + private final Map> strictEntityDescriptorMap; + private final Map> embeddableDescriptorMap; + private final Map entityProxyInterfaceMap = new ConcurrentHashMap<>(); + + private final Map nameToImportNameMap = new ConcurrentHashMap<>(); + private final Map> polymorphicEntityReferenceMap = new ConcurrentHashMap<>(); + + public JpaMetamodelImpl(TypeConfiguration typeConfiguration) { + this.typeConfiguration = typeConfiguration; + } + + @Override + public EntityDomainType resolveHqlEntityReference(String entityName) { + final String rename = resolveImportedName( entityName ); + if ( rename != null ) { + entityName = rename; + } + + final EntityDomainType entityDescriptor = entity( entityName ); + if ( entityDescriptor != null ) { + return entityDescriptor; + } + + final Class requestedClass = resolveRequestedClass( entityName ); + if ( requestedClass != null ) { + return resolveEntityReference( requestedClass ); + } + + throw new IllegalArgumentException( "Could not resolve entity reference " + entityName ); + } + + private String resolveImportedName(String name) { + String result = nameToImportNameMap.get( name ); + if ( result == null ) { + // see if the name is a fully-qualified class name + try { + getServiceRegistry().getService( ClassLoaderService.class ).classForName( name ); + + // it is a fully-qualified class name - add it to the cache + // so we do not keep trying later + nameToImportNameMap.put( name, name ); + return name; + } + catch ( ClassLoadingException cnfe ) { + // it is a NOT fully-qualified class name - add a marker entry + // so we do not keep trying later + nameToImportNameMap.put( name, INVALID_IMPORT ); + return null; + } + } + else { + // explicitly check for same instance + //noinspection StringEquality + if ( result == INVALID_IMPORT ) { + return null; + } + else { + return result; + } + } + } + + private Class resolveRequestedClass(String entityName) { + try { + return getServiceRegistry().getService( ClassLoaderService.class ).classForName( entityName ); + } + catch (ClassLoadingException e) { + return null; + } + } + + @SuppressWarnings("unchecked") + public EntityDomainType resolveEntityReference(Class javaType) { + // try the incoming Java type as a "strict" entity reference + { + final EntityDomainType descriptor = strictEntityDescriptorMap.get( javaType ); + if ( descriptor != null ) { + return (EntityDomainType) descriptor; + } + } + + // Next, try it as a proxy interface reference + { + final String proxyEntityName = entityProxyInterfaceMap.get( javaType ); + if ( proxyEntityName != null ) { + return (EntityDomainType) entityDescriptorMap.get( proxyEntityName ); + } + } + + // otherwise, try to handle it as a polymorphic reference + { + if ( polymorphicEntityReferenceMap.containsKey( javaType ) ) { + return (EntityDomainType) polymorphicEntityReferenceMap.get( javaType ); + } + + final Set> matchingDescriptors = new HashSet<>(); + visitEntityTypes( + entityDomainType -> { + if ( javaType.isAssignableFrom( entityDomainType.getJavaType() ) ) { + matchingDescriptors.add( entityDomainType ); + } + } + ); + if ( !matchingDescriptors.isEmpty() ) { + final SqmPolymorphicRootDescriptor descriptor = new SqmPolymorphicRootDescriptor( + typeConfiguration.getJavaTypeDescriptorRegistry().resolveDescriptor( javaType ), + matchingDescriptors + ); + polymorphicEntityReferenceMap.put( javaType, descriptor ); + return descriptor; + } + } + + throw new IllegalArgumentException( "Could not resolve entity reference : " + javaType.getName() ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/ListAttributeImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/ListAttributeImpl.java index 6ca0766507..7fd5fa8438 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/ListAttributeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/ListAttributeImpl.java @@ -8,6 +8,7 @@ package org.hibernate.metamodel.model.domain.internal; 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; @@ -22,10 +23,17 @@ import org.hibernate.query.sqm.tree.from.SqmFrom; class ListAttributeImpl extends AbstractPluralAttribute, E> implements ListPersistentAttribute { private final SqmPathSource indexPathSource; - ListAttributeImpl(PluralAttributeBuilder, E, ?> xceBuilder) { - super( xceBuilder ); + ListAttributeImpl(PluralAttributeBuilder, E, ?> builder) { + super( builder ); - indexPathSource = + //noinspection unchecked + this.indexPathSource = (SqmPathSource) DomainModelHelper.resolveSqmPathSource( + ValueClassification.BASIC, + getName(), + builder.getListIndexOrMapKeyType(), + BindableType.PLURAL_ATTRIBUTE, + builder.getNodeBuilder() + ); } @Override @@ -33,6 +41,11 @@ class ListAttributeImpl extends AbstractPluralAttribute, E> imp return CollectionType.LIST; } + @Override + public SqmPathSource getIndexPathSource() { + return indexPathSource; + } + @Override public SqmAttributeJoin createSqmJoin( SqmFrom lhs, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MappedSuperclassTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MappedSuperclassTypeImpl.java index ea2512f8cd..9df376c85f 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MappedSuperclassTypeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MappedSuperclassTypeImpl.java @@ -7,12 +7,11 @@ package org.hibernate.metamodel.model.domain.internal; import org.hibernate.cfg.NotYetImplementedException; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.graph.spi.SubGraphImplementor; import org.hibernate.mapping.MappedSuperclass; -import org.hibernate.metamodel.RepresentationMode; import org.hibernate.metamodel.model.domain.AbstractIdentifiableType; import org.hibernate.metamodel.model.domain.IdentifiableDomainType; +import org.hibernate.metamodel.model.domain.JpaMetamodel; import org.hibernate.metamodel.model.domain.MappedSuperclassDomainType; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; @@ -25,7 +24,7 @@ public class MappedSuperclassTypeImpl extends AbstractIdentifiableType imp JavaTypeDescriptor javaTypeDescriptor, MappedSuperclass mappedSuperclass, IdentifiableDomainType superType, - SessionFactoryImplementor sessionFactory) { + JpaMetamodel jpaMetamodel) { super( javaTypeDescriptor.getJavaType().getName(), javaTypeDescriptor, @@ -33,7 +32,7 @@ public class MappedSuperclassTypeImpl extends AbstractIdentifiableType imp mappedSuperclass.getDeclaredIdentifierMapper() != null || ( superType != null && superType.hasIdClass() ), mappedSuperclass.hasIdentifierProperty(), mappedSuperclass.isVersioned(), - sessionFactory + jpaMetamodel ); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/PluralAttributeBuilder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/PluralAttributeBuilder.java index 58bc76d092..9142788ff3 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/PluralAttributeBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/PluralAttributeBuilder.java @@ -13,8 +13,8 @@ import java.util.Map; import java.util.Set; import org.hibernate.mapping.Property; -import org.hibernate.metamodel.CollectionClassification; import org.hibernate.metamodel.AttributeClassification; +import org.hibernate.metamodel.CollectionClassification; import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.SimpleDomainType; import org.hibernate.query.sqm.NodeBuilder; @@ -29,7 +29,7 @@ public class PluralAttributeBuilder { private final NodeBuilder nodeBuilder; - private SimpleDomainType keyType; + private SimpleDomainType listIndexOrMapKeyType; private AttributeClassification attributeClassification; private CollectionClassification collectionClassification; @@ -42,12 +42,12 @@ public class PluralAttributeBuilder { ManagedDomainType ownerType, SimpleDomainType elementType, JavaTypeDescriptor collectionJavaTypeDescriptor, - SimpleDomainType keyType, + SimpleDomainType listIndexOrMapKeyType, NodeBuilder nodeBuilder) { this.declaringType = ownerType; this.valueType = elementType; this.collectionJavaTypeDescriptor = collectionJavaTypeDescriptor; - this.keyType = keyType; + this.listIndexOrMapKeyType = listIndexOrMapKeyType; this.nodeBuilder = nodeBuilder; } @@ -67,8 +67,8 @@ public class PluralAttributeBuilder { return collectionClassification; } - public SimpleDomainType getKeyType() { - return keyType; + public SimpleDomainType getListIndexOrMapKeyType() { + return listIndexOrMapKeyType; } public JavaTypeDescriptor getCollectionJavaTypeDescriptor() { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/SingularAttributeImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/SingularAttributeImpl.java index 3d6751e162..06823f6a32 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/SingularAttributeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/SingularAttributeImpl.java @@ -90,6 +90,11 @@ public class SingularAttributeImpl } } + @Override + public String getPathName() { + return getName(); + } + @Override public SimpleDomainType getSqmPathType() { //noinspection unchecked diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/RuntimeModel.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/RuntimeModel.java new file mode 100644 index 0000000000..b64a1ed0f8 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/RuntimeModel.java @@ -0,0 +1,175 @@ +/* + * 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.spi; + +import java.util.List; +import java.util.function.Consumer; + +import org.hibernate.graph.RootGraph; +import org.hibernate.metamodel.model.domain.EntityDomainType; +import org.hibernate.metamodel.model.domain.NavigableRole; +import org.hibernate.persister.collection.CollectionPersister; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.type.spi.TypeConfiguration; + +/** + * Access to information about Hibernate's runtime type system + * + * @author Steve Ebersole + */ +public interface RuntimeModel { + TypeConfiguration getTypeConfiguration(); + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Entity descriptors + + /** + * Given a JPA entity domain type, get the associated Hibernate entity descriptor + */ + EntityPersister resolveEntityDescriptor(EntityDomainType entityDomainType); + + /** + * Visit all entity mapping descriptors defined in the model + */ + void visitEntityDescriptors(Consumer action); + + /** + * Get an entity mapping descriptor based on its Hibernate entity-name + * + * @throws IllegalArgumentException if the name does not refer to an entity + * + * @see #findEntityDescriptor + */ + EntityPersister getEntityDescriptor(String entityName); + + /** + * Get an entity mapping descriptor based on its NavigableRole. + * + * @throws IllegalArgumentException if the name does not refer to an entity + * + * @see #findEntityDescriptor + */ + EntityPersister getEntityDescriptor(NavigableRole name); + + /** + * Get an entity mapping descriptor based on its Class. + * + * @throws IllegalArgumentException if the name does not refer to an entity + * + * @see #findEntityDescriptor + */ + EntityPersister getEntityDescriptor(Class entityJavaType); + + /** + * Find an entity mapping descriptor based on its Hibernate entity-name. + * + * @apiNote Returns {@code null} rather than throwing exception + */ + EntityPersister findEntityDescriptor(String entityName); + + /** + * Find an entity mapping descriptor based on its Class. + * + * @apiNote Returns {@code null} rather than throwing exception + */ + EntityPersister findEntityDescriptor(Class entityJavaType); + + /** + * Locate an entity mapping descriptor by Class. The passed Class might + * refer to either the entity Class directly, or it might name a proxy + * interface for the entity. This method accounts for both, preferring the + * direct entity name. + * + * @throws org.hibernate.UnknownEntityTypeException If a matching EntityPersister cannot be located + */ + EntityPersister locateEntityDescriptor(Class byClass); + + /** + * @see #locateEntityDescriptor + * + * @deprecated (since 6.0) use {@link #locateEntityDescriptor(Class)} instead + */ + @Deprecated + default EntityPersister locateEntityPersister(Class byClass) { + return locateEntityDescriptor( byClass ); + } + + /** + * Locate the entity persister by name. + * + * @return The located EntityPersister, never {@code null} + * + * @throws org.hibernate.UnknownEntityTypeException If a matching EntityPersister cannot be located + * + * @deprecated (since 6.0) - use {@link #getEntityDescriptor(String)} instead + */ + @Deprecated + EntityPersister locateEntityPersister(String byName); + + String getImportedName(String name); + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Collection descriptors + + /** + * Visit the mapping descriptors for all collections defined in the model + */ + void visitCollectionDescriptors(Consumer action); + + /** + * Get a collection mapping descriptor based on its role + * + * @throws IllegalArgumentException if the role does not refer to a collection + * + * @see #findCollectionDescriptor + */ + CollectionPersister getCollectionDescriptor(String role); + + /** + * Get a collection mapping descriptor based on its role + * + * @throws IllegalArgumentException if the role does not refer to a collection + * + * @see #findCollectionDescriptor + */ + CollectionPersister getCollectionDescriptor(NavigableRole role); + + /** + * Find a collection mapping descriptor based on its role. Returns + * {@code null} if the role does not refer to a collection + * + * @see #findCollectionDescriptor + */ + CollectionPersister findCollectionDescriptor(NavigableRole role); + + /** + * Find a collection mapping descriptor based on its role. Returns + * {@code null} if the role does not refer to a collection + * + * @see #findCollectionDescriptor + */ + CollectionPersister findCollectionDescriptor(String role); + + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // JPA entity graphs + + RootGraph findNamedGraph(String name); + void visitNamedGraphs(Consumer> action); + + RootGraph defaultGraph(String entityName); + RootGraph defaultGraph(Class entityJavaType); + RootGraph defaultGraph(EntityPersister entityDescriptor); + RootGraph defaultGraph(EntityDomainType entityDomainType); + + List> findRootGraphsForType(Class baseEntityJavaType); + List> findRootGraphsForType(String baseEntityName); + List> findRootGraphsForType(EntityPersister baseEntityDescriptor); + +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/ComparisonOperator.java b/hibernate-core/src/main/java/org/hibernate/query/ComparisonOperator.java new file mode 100644 index 0000000000..1ff9e3d46c --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/ComparisonOperator.java @@ -0,0 +1,82 @@ +/* + * 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.query; + +/** + * Defines the comparison operators. We could also get away with + * only 3 and use negation... + */ +public enum ComparisonOperator { + EQUAL { + public ComparisonOperator negated() { + return NOT_EQUAL; + } + + @Override + public String sqlText() { + return "="; + } + }, + + NOT_EQUAL { + public ComparisonOperator negated() { + return EQUAL; + } + + @Override + public String sqlText() { + return "!="; + } + }, + + LESS_THAN { + public ComparisonOperator negated() { + return GREATER_THAN_OR_EQUAL; + } + + @Override + public String sqlText() { + return "<"; + } + }, + + LESS_THAN_OR_EQUAL { + public ComparisonOperator negated() { + return GREATER_THAN; + } + + @Override + public String sqlText() { + return "<="; + } + }, + + GREATER_THAN { + public ComparisonOperator negated() { + return LESS_THAN_OR_EQUAL; + } + + @Override + public String sqlText() { + return ">"; + } + }, + + GREATER_THAN_OR_EQUAL { + public ComparisonOperator negated() { + return LESS_THAN; + } + + @Override + public String sqlText() { + return ">="; + } + }; + + public abstract ComparisonOperator negated(); + public abstract String sqlText(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/DynamicInstantiationNature.java b/hibernate-core/src/main/java/org/hibernate/query/DynamicInstantiationNature.java new file mode 100644 index 0000000000..50f3162d92 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/DynamicInstantiationNature.java @@ -0,0 +1,37 @@ +/* + * 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.query; + +import java.util.List; +import java.util.Map; + +/** + * Represents the type of instantiation to be performed. + * + * @author Steve Ebersole + */ +public enum DynamicInstantiationNature { + /** + * The target names a Class to be instantiated. This is the only form + * of dynamic instantiation that is JPA-compliant. + */ + CLASS, + /** + * The target identified a {@link Map} instantiation. The + * result for each "row" will be a Map whose key is the alias (or name + * of the selected attribute is no alias) and whose value is the + * corresponding value read from the JDBC results. Similar to JPA's + * named-Tuple support. + */ + MAP, + /** + * The target identified a {@link List} instantiation. The + * result for each "row" will be a List rather than an array. Similar + * to JPA's positional-Tuple support. + */ + LIST +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/HqlParseTreeBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/HqlParseTreeBuilder.java new file mode 100644 index 0000000000..8b6310d475 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/HqlParseTreeBuilder.java @@ -0,0 +1,40 @@ +/* + * 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.query.hql.internal; + +import org.jboss.logging.Logger; + +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.Token; + +/** + * Leverages Antlr to build a parse tree from an HQL query + * + * @author Steve Ebersole + */ +public class HqlParseTreeBuilder { + private static final Logger log = Logger.getLogger( HqlParseTreeBuilder.class ); + + /** + * Singleton access + */ + public static final HqlParseTreeBuilder INSTANCE = new HqlParseTreeBuilder(); + + public HqlParser parseHql(String hql) { + // Build the lexer + HqlLexer hqlLexer = new HqlLexer( CharStreams.fromString( hql ) ); + + // Build the parser... + return new HqlParser( new CommonTokenStream( hqlLexer ) ) { + @Override + protected void logUseOfReservedWordAsIdentifier(Token token) { + log.debugf( "Encountered use of reserved word as identifier : " + token.getText() ); + } + }; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/HqlParseTreePrinter.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/HqlParseTreePrinter.java new file mode 100644 index 0000000000..b812fa7012 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/HqlParseTreePrinter.java @@ -0,0 +1,133 @@ +/* + * 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.query.hql.internal; + +import org.hibernate.query.QueryLogger; + +import org.jboss.logging.Logger; + +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.tree.ParseTreeWalker; + +/** + * Used to + * @author Steve Ebersole + */ +@SuppressWarnings("WeakerAccess") +public class HqlParseTreePrinter extends HqlParserBaseListener { + private static final Logger HQL_LOGGER = QueryLogger.subLogger( "hql.parseTree" ); + private static final boolean LOG_DEBUG_ENABLED = HQL_LOGGER.isDebugEnabled(); + + public static void logStatementParseTree(HqlParser parser) { + if ( !LOG_DEBUG_ENABLED ) { + return; + } + + final HqlParseTreePrinter walker = new HqlParseTreePrinter( parser ); + ParseTreeWalker.DEFAULT.walk( walker, parser.statement() ); + + HQL_LOGGER.debugf( "HQL parse-tree:\n%s", walker.buffer.toString() ); + + parser.reset(); + } + + public static void logOrderByParseTree(HqlParser parser) { + if ( !LOG_DEBUG_ENABLED ) { + return; + } + + final HqlParseTreePrinter walker = new HqlParseTreePrinter( parser ); + ParseTreeWalker.DEFAULT.walk( walker, parser.orderByClause() ); + + HQL_LOGGER.debugf( "Mapping order-by parse-tree:\n%s", walker.buffer.toString() ); + + parser.reset(); + } + + private final HqlParser parser; + private final StringBuffer buffer = new StringBuffer(); + private int depth = 2; + + public HqlParseTreePrinter(HqlParser parser) { + this.parser = parser; + } + + private enum LineType { + ENTER, + EXIT + } + + @Override + public void enterEveryRule(ParserRuleContext ctx) { + final String ruleName = parser.getRuleNames()[ctx.getRuleIndex()]; + + if ( !ruleName.endsWith( "Keyword" ) ) { + applyLine( LineType.ENTER, ruleName, ruleTypeName( ctx.getClass() ), ctx.getText() ); + } + + super.enterEveryRule( ctx ); + } + + private String ruleTypeName(Class ruleCtxClass) { + final String name = ruleCtxClass.getSimpleName(); + + final int position = name.lastIndexOf( "Context" ); + if ( position > 1 ) { + return name.substring( 0, position ); + } + else { + // todo (6.0) : does this ever happen? + return name; + } + } + + private void applyLine( + LineType lineType, + String ruleName, + String ruleTypeName, + String ctxText) { + applyLinePadding( lineType ); + + buffer.append( '[' ).append( ruleName ); + + if ( ! ruleTypeName.equalsIgnoreCase( ruleName ) ) { + buffer.append( " (" ).append( ruleTypeName ).append( ')' ); + } + + buffer.append( ']' ) + .append( " - `" ).append( ctxText ).append( '`' ) + .append( '\n' ); + } + + private void applyLinePadding(LineType lineType) { + if ( lineType == LineType.ENTER ) { + pad( depth++ ); + buffer.append( "-> " ); + } + else { + pad( --depth ); + buffer.append( "<- " ); + } + + } + + private String pad(int depth) { + for ( int i = 0; i < depth; i++ ) { + buffer.append( " " ); + } + return buffer.toString(); + } + + @Override + public void exitEveryRule(ParserRuleContext ctx) { + super.exitEveryRule( ctx ); + + final String ruleName = parser.getRuleNames()[ctx.getRuleIndex()]; + + applyLine( LineType.EXIT, ruleName, ruleTypeName( ctx.getClass() ), ctx.getText() ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java index ca5efee831..8cd6e15479 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java @@ -21,26 +21,16 @@ import org.hibernate.NullPrecedence; import org.hibernate.SortOrder; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; -import org.hibernate.collection.spi.CollectionClassification; import org.hibernate.internal.util.collections.Stack; import org.hibernate.internal.util.collections.StandardStack; -import org.hibernate.metamodel.model.mapping.EntityTypeDescriptor; -import org.hibernate.metamodel.model.mapping.IdentifiableTypeDescriptor; -import org.hibernate.metamodel.model.mapping.PersistentCollectionDescriptor; -import org.hibernate.metamodel.model.mapping.spi.AllowableFunctionReturnType; -import org.hibernate.metamodel.model.mapping.spi.BagPersistentAttribute; -import org.hibernate.metamodel.model.mapping.spi.EntityValuedNavigable; -import org.hibernate.metamodel.model.mapping.spi.ListPersistentAttribute; -import org.hibernate.metamodel.model.mapping.spi.MapPersistentAttribute; -import org.hibernate.metamodel.model.mapping.spi.Navigable; -import org.hibernate.metamodel.model.mapping.spi.NavigableContainer; -import org.hibernate.metamodel.model.mapping.spi.PluralValuedNavigable; -import org.hibernate.metamodel.model.mapping.spi.SingularPersistentAttribute; +import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; +import org.hibernate.metamodel.model.domain.EntityDomainType; +import org.hibernate.metamodel.model.domain.PluralPersistentAttribute; import org.hibernate.query.BinaryArithmeticOperator; +import org.hibernate.query.ComparisonOperator; import org.hibernate.query.QueryLogger; import org.hibernate.query.UnaryArithmeticOperator; import org.hibernate.query.hql.DotIdentifierConsumer; -import org.hibernate.query.spi.ComparisonOperator; import org.hibernate.query.sqm.LiteralNumberFormatException; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.ParsingException; @@ -143,12 +133,8 @@ import org.hibernate.query.sqm.tree.select.SqmSortSpecification; import org.hibernate.query.sqm.tree.select.SqmSubQuery; import org.hibernate.query.sqm.tree.update.SqmUpdateStatement; import org.hibernate.sql.TrimSpec; -import org.hibernate.sql.ast.produce.metamodel.spi.BasicValuedExpressableType; -import org.hibernate.sql.ast.produce.metamodel.spi.EntityValuedExpressableType; -import org.hibernate.sql.ast.produce.metamodel.spi.ExpressableType; import org.hibernate.type.StandardBasicTypes; -import org.hibernate.type.descriptor.java.spi.BasicJavaDescriptor; -import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptor; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.jboss.logging.Logger; @@ -326,7 +312,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre @Override public SqmInsertSelectStatement visitInsertStatement(HqlParser.InsertStatementContext ctx) { - final EntityTypeDescriptor targetType = visitEntityName( ctx.insertSpec().intoSpec().entityName() ); + final EntityDomainType targetType = visitEntityName( ctx.insertSpec().intoSpec().entityName() ); final SqmRoot root = new SqmRoot<>( targetType, null, creationContext.getNodeBuilder() ); processingStateStack.getCurrent().getPathRegistry().register( root ); @@ -636,7 +622,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre final JavaTypeDescriptor jtd = creationContext.getDomainModel() .getTypeConfiguration() .getJavaTypeDescriptorRegistry() - .getOrMakeJavaDescriptor( targetJavaType ); + .resolveDescriptor( targetJavaType ); dynamicInstantiation = SqmDynamicInstantiation.forClassInstantiation( jtd, creationContext.getNodeBuilder() @@ -837,21 +823,21 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre } @Override - public EntityTypeDescriptor visitEntityName(HqlParser.EntityNameContext parserEntityName) { + public EntityDomainType visitEntityName(HqlParser.EntityNameContext parserEntityName) { final String entityName = parserEntityName.dotIdentifierSequence().getText(); - final EntityValuedExpressableType entityReference = resolveEntityReference( entityName ); + final EntityDomainType entityReference = resolveEntityReference( entityName ); if ( entityReference == null ) { throw new UnknownEntityException( "Could not resolve entity name [" + entityName + "] as DML target", entityName ); } - return entityReference.getEntityDescriptor(); + return entityReference; } - private EntityValuedExpressableType resolveEntityReference(String entityName) { + private EntityDomainType resolveEntityReference(String entityName) { log.debugf( "Attempting to resolve path [%s] as entity reference...", entityName ); - EntityValuedExpressableType reference = null; + EntityDomainType reference = null; try { - reference = creationContext.getDomainModel().resolveEntityReference( entityName ); + reference = creationContext.getDomainModel().entity( entityName ); } catch (Exception ignore) { } @@ -904,12 +890,12 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre log.debugf( "Handling root path - %s", name ); - final EntityTypeDescriptor entityDescriptor = getCreationContext().getDomainModel().resolveEntityReference( name ); + final EntityDomainType entityDescriptor = getCreationContext().getDomainModel().resolveHqlEntityReference( name ); if ( entityDescriptor instanceof SqmPolymorphicRootDescriptor ) { if ( getCreationOptions().useStrictJpaCompliance() ) { throw new StrictJpaComplianceViolation( - "Encountered unmapped polymorphic reference [" + entityDescriptor.getEntityName() + "Encountered unmapped polymorphic reference [" + entityDescriptor.getHibernateEntityName() + "], but strict JPQL compliance was requested", StrictJpaComplianceViolation.Type.UNMAPPED_POLYMORPHISM ); @@ -974,21 +960,21 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre throw new UnsupportedOperationException( "Unexpected call to #visitCrossJoin, see #consumeCrossJoin" ); } + @SuppressWarnings("unchecked") private void consumeCrossJoin(HqlParser.CrossJoinContext parserJoin, SqmRoot sqmRoot) { final String name = parserJoin.pathRoot().entityName().getText(); SqmTreeCreationLogger.LOGGER.debugf( "Handling root path - %s", name ); - final EntityValuedExpressableType entityType = getCreationContext().getDomainModel().resolveEntityReference( name ); + final EntityDomainType entityDescriptor = getCreationContext().getDomainModel().resolveHqlEntityReference( name ); - if ( entityType instanceof SqmPolymorphicRootDescriptor ) { + if ( entityDescriptor instanceof SqmPolymorphicRootDescriptor ) { throw new SemanticException( "Unmapped polymorphic reference cannot be used as a CROSS JOIN target" ); } - final EntityTypeDescriptor entityDescriptor = entityType.getEntityDescriptor(); - final SqmCrossJoin join = new SqmCrossJoin( - entityDescriptor, visitIdentificationVariableDef( parserJoin.pathRoot().identificationVariableDef() ), + entityDescriptor, + visitIdentificationVariableDef( parserJoin.pathRoot().identificationVariableDef() ), sqmRoot ); @@ -1236,7 +1222,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre public SqmPredicate visitMemberOfPredicate(HqlParser.MemberOfPredicateContext ctx) { final SqmPath sqmPluralPath = consumeDomainPath( ctx.path() ); - if ( sqmPluralPath.getReferencedPathSource() instanceof PluralValuedNavigable ) { + if ( sqmPluralPath.getReferencedPathSource() instanceof PluralPersistentAttribute ) { return new SqmMemberOfPredicate( sqmPluralPath, creationContext.getNodeBuilder() ); } else { diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryProducerImpl.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryProducerImpl.java new file mode 100644 index 0000000000..9706dff6bd --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryProducerImpl.java @@ -0,0 +1,62 @@ +/* + * 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.query.hql.internal; + +import org.hibernate.QueryException; +import org.hibernate.query.sqm.InterpretationException; +import org.hibernate.query.hql.SemanticQueryProducer; +import org.hibernate.query.sqm.produce.internal.SqmTreePrinter; +import org.hibernate.query.sqm.produce.spi.SqmCreationContext; +import org.hibernate.query.sqm.produce.spi.SqmCreationOptions; +import org.hibernate.query.sqm.tree.SqmStatement; + +/** + * Standard implementation of SemanticQueryInterpreter + * + * @author Steve Ebersole + */ +public class SemanticQueryProducerImpl implements SemanticQueryProducer { + private final SqmCreationContext sqmCreationContext; + private final SqmCreationOptions sqmCreationOptions; + + public SemanticQueryProducerImpl( + SqmCreationContext sqmCreationContext, + SqmCreationOptions sqmCreationOptions) { + this.sqmCreationContext = sqmCreationContext; + this.sqmCreationOptions = sqmCreationOptions; + } + + @Override + public SqmStatement interpret(String query) { +// final ParsingContext parsingContext = ; + + // first, ask Antlr to build the parse tree + final HqlParser parser = HqlParseTreeBuilder.INSTANCE.parseHql( query ); + + // Log the parse tree (if enabled) + HqlParseTreePrinter.logStatementParseTree( parser ); + + // then we perform semantic analysis and build the semantic representation... + try { + final SqmStatement sqmStatement = SemanticQueryBuilder.buildSemanticModel( + parser.statement(), + sqmCreationOptions, + sqmCreationContext + ); + + SqmTreePrinter.logTree( sqmStatement ); + + return sqmStatement; + } + catch (QueryException e) { + throw e; + } + catch (Exception e) { + throw new InterpretationException( query, e ); + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/NodeBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/NodeBuilder.java index f2006bd99f..b105593a64 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/NodeBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/NodeBuilder.java @@ -32,6 +32,7 @@ import javax.persistence.criteria.Subquery; import org.hibernate.NullPrecedence; import org.hibernate.SortOrder; import org.hibernate.metamodel.model.domain.DomainType; +import org.hibernate.metamodel.model.domain.JpaMetamodel; import org.hibernate.metamodel.spi.MetamodelImplementor; import org.hibernate.query.criteria.HibernateCriteriaBuilder; import org.hibernate.query.criteria.JpaCoalesce; @@ -71,7 +72,7 @@ import org.hibernate.type.spi.TypeConfiguration; */ @SuppressWarnings("unchecked") public interface NodeBuilder extends HibernateCriteriaBuilder { - MetamodelImplementor getDomainModel(); + JpaMetamodel getDomainModel(); default TypeConfiguration getTypeConfiguration() { return getDomainModel().getTypeConfiguration(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java index 12e0277bab..64db2d3bf5 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java @@ -37,8 +37,8 @@ import org.hibernate.QueryException; import org.hibernate.SortOrder; import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.metamodel.model.domain.DomainType; -import org.hibernate.metamodel.model.mapping.spi.AllowableFunctionReturnType; -import org.hibernate.metamodel.spi.MetamodelImplementor; +import org.hibernate.metamodel.model.domain.JpaMetamodel; +import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; import org.hibernate.query.BinaryArithmeticOperator; import org.hibernate.query.UnaryArithmeticOperator; import org.hibernate.query.criteria.JpaCoalesce; @@ -97,9 +97,7 @@ import org.hibernate.query.sqm.tree.select.SqmSubQuery; import org.hibernate.query.sqm.tree.update.SqmUpdateStatement; import org.hibernate.service.ServiceRegistry; import org.hibernate.sql.TrimSpec; -import org.hibernate.sql.ast.produce.metamodel.spi.BasicValuedExpressableType; import org.hibernate.query.sqm.tree.expression.function.SqmFunction; -import org.hibernate.type.spi.StandardSpiBasicTypes; import static java.util.Arrays.asList; import static org.hibernate.query.internal.QueryHelper.highestPrecedenceType; @@ -112,12 +110,12 @@ import static org.hibernate.query.internal.QueryHelper.highestPrecedenceType; */ public class SqmCriteriaNodeBuilder implements NodeBuilder { private final QueryEngine queryEngine; - private final MetamodelImplementor domainModel; + private final JpaMetamodel domainModel; private final ServiceRegistry serviceRegistry; public SqmCriteriaNodeBuilder( QueryEngine queryEngine, - MetamodelImplementor domainModel, + JpaMetamodel domainModel, ServiceRegistry serviceRegistry) { this.queryEngine = queryEngine; this.domainModel = domainModel; @@ -125,7 +123,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder { } @Override - public MetamodelImplementor getDomainModel() { + public JpaMetamodel getDomainModel() { return domainModel; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/spi/SqmCreationContext.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/spi/SqmCreationContext.java index 86f7c9ef6b..468943dd98 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/spi/SqmCreationContext.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/spi/SqmCreationContext.java @@ -7,7 +7,7 @@ package org.hibernate.query.sqm.produce.spi; import org.hibernate.Incubating; -import org.hibernate.metamodel.spi.MetamodelImplementor; +import org.hibernate.metamodel.model.domain.JpaMetamodel; import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.service.ServiceRegistry; @@ -22,12 +22,14 @@ public interface SqmCreationContext { /** * Access to the domain model metadata */ - MetamodelImplementor getDomainModel(); + JpaMetamodel getDomainModel(); /** * Access to the ServiceRegistry for the context */ - ServiceRegistry getServiceRegistry(); + default ServiceRegistry getServiceRegistry() { + return getDomainModel().getServiceRegistry(); + } QueryEngine getQueryEngine(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPolymorphicRootDescriptor.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPolymorphicRootDescriptor.java index d6da3b6270..b9a3b344fe 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPolymorphicRootDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPolymorphicRootDescriptor.java @@ -23,14 +23,12 @@ import javax.persistence.metamodel.PluralAttribute; import javax.persistence.metamodel.SetAttribute; import javax.persistence.metamodel.SingularAttribute; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.graph.spi.SubGraphImplementor; import org.hibernate.metamodel.RepresentationMode; import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.IdentifiableDomainType; import org.hibernate.metamodel.model.domain.ManagedDomainType; -import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.metamodel.model.domain.PersistentAttribute; import org.hibernate.metamodel.model.domain.PluralPersistentAttribute; import org.hibernate.metamodel.model.domain.SimpleDomainType; @@ -38,7 +36,6 @@ import org.hibernate.metamodel.model.domain.SingularPersistentAttribute; import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.produce.spi.SqmCreationState; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; -import org.hibernate.type.spi.TypeConfiguration; /** * Acts as the EntityValuedNavigable for a "polymorphic query" grouping @@ -49,17 +46,12 @@ public class SqmPolymorphicRootDescriptor implements EntityDomainType { private final Set> implementors; private final Map> commonAttributes; - private final NavigableRole navigableRole; private final JavaTypeDescriptor polymorphicJavaDescriptor; - private final SessionFactoryImplementor sessionFactory; public SqmPolymorphicRootDescriptor( JavaTypeDescriptor polymorphicJavaDescriptor, - Set> implementors, - SessionFactoryImplementor sessionFactory) { + Set> implementors) { this.polymorphicJavaDescriptor = polymorphicJavaDescriptor; - this.navigableRole = new NavigableRole( polymorphicJavaDescriptor.getJavaType().getName() ); - this.sessionFactory = sessionFactory; this.implementors = implementors; @@ -99,14 +91,6 @@ public class SqmPolymorphicRootDescriptor implements EntityDomainType { return new HashSet<>( implementors ); } - public SessionFactoryImplementor getFactory() { - return sessionFactory; - } - - public TypeConfiguration getTypeConfiguration() { - return getFactory().getMetamodel().getTypeConfiguration(); - } - @Override public String getName() { return polymorphicJavaDescriptor.getJavaType().getName(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmComparisonPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmComparisonPredicate.java index 271ae1930f..3623afbae6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmComparisonPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmComparisonPredicate.java @@ -6,12 +6,12 @@ */ package org.hibernate.query.sqm.tree.predicate; +import org.hibernate.query.ComparisonOperator; import org.hibernate.query.internal.QueryHelper; -import org.hibernate.query.spi.ComparisonOperator; import org.hibernate.query.sqm.NodeBuilder; +import org.hibernate.query.sqm.SqmExpressable; import org.hibernate.query.sqm.consume.spi.SemanticQueryWalker; import org.hibernate.query.sqm.tree.expression.SqmExpression; -import org.hibernate.sql.ast.produce.metamodel.spi.ExpressableType; /** * @author Steve Ebersole @@ -31,12 +31,14 @@ public class SqmComparisonPredicate extends AbstractNegatableSqmPredicate { this.rightHandExpression = rightHandExpression; this.operator = operator; - final ExpressableType expressableType = QueryHelper.highestPrecedenceType( + final SqmExpressable expressableType = QueryHelper.highestPrecedenceType( leftHandExpression.getNodeType(), rightHandExpression.getNodeType() ); + //noinspection unchecked leftHandExpression.applyInferableType( expressableType ); + //noinspection unchecked rightHandExpression.applyInferableType( expressableType ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmDynamicInstantiation.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmDynamicInstantiation.java index 1e208a2bd7..be91a5b083 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmDynamicInstantiation.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmDynamicInstantiation.java @@ -11,21 +11,20 @@ import java.util.List; import java.util.Map; import java.util.function.Consumer; +import org.hibernate.query.DynamicInstantiationNature; import org.hibernate.query.criteria.JpaCompoundSelection; import org.hibernate.query.criteria.JpaSelection; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.consume.spi.SemanticQueryWalker; import org.hibernate.query.sqm.tree.expression.SqmExpression; import org.hibernate.query.sqm.tree.jpa.AbstractJpaSelection; -import org.hibernate.sql.ast.produce.metamodel.spi.ExpressableType; -import org.hibernate.sql.ast.tree.expression.instantiation.DynamicInstantiationNature; -import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptor; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.jboss.logging.Logger; -import static org.hibernate.sql.ast.tree.expression.instantiation.DynamicInstantiationNature.CLASS; -import static org.hibernate.sql.ast.tree.expression.instantiation.DynamicInstantiationNature.LIST; -import static org.hibernate.sql.ast.tree.expression.instantiation.DynamicInstantiationNature.MAP; +import static org.hibernate.query.DynamicInstantiationNature.CLASS; +import static org.hibernate.query.DynamicInstantiationNature.LIST; +import static org.hibernate.query.DynamicInstantiationNature.MAP; /** * Represents a dynamic instantiation ({@code select new XYZ(...) ...}) as part of the SQM. @@ -166,13 +165,12 @@ public class SqmDynamicInstantiation } @Override - @SuppressWarnings("unchecked") public X accept(SemanticQueryWalker walker) { return walker.visitDynamicInstantiation( this ); } - public SqmDynamicInstantiation makeShallowCopy() { - return new SqmDynamicInstantiation( getInstantiationTarget(), nodeBuilder() ); + public SqmDynamicInstantiation makeShallowCopy() { + return new SqmDynamicInstantiation<>( getInstantiationTarget(), nodeBuilder() ); } private static class DynamicInstantiationTargetImpl implements SqmDynamicInstantiationTarget { @@ -196,14 +194,9 @@ public class SqmDynamicInstantiation } @Override - public JavaTypeDescriptor getJavaTypeDescriptor() { + public JavaTypeDescriptor getExpressableJavaTypeDescriptor() { return getTargetTypeDescriptor(); } - - @Override - public PersistenceType getPersistenceType() { - return PersistenceType.BASIC; - } } @@ -224,6 +217,11 @@ public class SqmDynamicInstantiation return list; } + @Override + public String getAlias() { + return null; + } + @Override public JpaSelection alias(String name) { return null; @@ -233,19 +231,4 @@ public class SqmDynamicInstantiation public boolean isCompoundSelection() { return false; } - - @Override - public String getAlias() { - return null; - } - - @Override - public NodeBuilder nodeBuilder() { - return null; - } - - @Override - public ExpressableType getNodeType() { - return null; - } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmDynamicInstantiationTarget.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmDynamicInstantiationTarget.java index 7523740fb7..d213fe5ae0 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmDynamicInstantiationTarget.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmDynamicInstantiationTarget.java @@ -6,9 +6,10 @@ */ package org.hibernate.query.sqm.tree.select; -import org.hibernate.sql.ast.produce.metamodel.spi.ExpressableType; -import org.hibernate.sql.ast.tree.expression.instantiation.DynamicInstantiationNature; -import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptor; + +import org.hibernate.query.DynamicInstantiationNature; +import org.hibernate.query.sqm.SqmExpressable; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** * Represents the thing-to-be-instantiated in a dynamic instantiation expression. Hibernate @@ -16,7 +17,7 @@ import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptor; * * @author Steve Ebersole */ -public interface SqmDynamicInstantiationTarget extends ExpressableType { +public interface SqmDynamicInstantiationTarget extends SqmExpressable { /** * Retrieves the enum describing the nature of this target. diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/MapEntryJavaDescriptor.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/MapEntryJavaDescriptor.java new file mode 100644 index 0000000000..1f3bd38e9a --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/MapEntryJavaDescriptor.java @@ -0,0 +1,48 @@ +/* + * 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.type.descriptor.java.spi; + +import java.util.Map; + +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.type.descriptor.java.AbstractTypeDescriptor; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptorIndicators; + +/** + * @author Steve Ebersole + */ +public class MapEntryJavaDescriptor extends AbstractTypeDescriptor { + /** + * Singleton access + */ + public static final MapEntryJavaDescriptor INSTANCE = new MapEntryJavaDescriptor(); + + public MapEntryJavaDescriptor() { + super( Map.Entry.class ); + } + + @Override + public SqlTypeDescriptor getJdbcRecommendedSqlType(SqlTypeDescriptorIndicators context) { + throw new UnsupportedOperationException( "Unsupported attempt to resolve JDBC type for Map.Entry" ); + } + + @Override + public Map.Entry fromString(String string) { + throw new UnsupportedOperationException( "Unsupported attempt create Map.Entry from String" ); + } + + @Override + public X unwrap(Map.Entry value, Class type, SharedSessionContractImplementor session) { + throw new UnsupportedOperationException( "Unsupported attempt to unwrap Map.Entry value" ); + } + + @Override + public Map.Entry wrap(X value, SharedSessionContractImplementor session) { + throw new UnsupportedOperationException( "Unsupported attempt to wrap Map.Entry value" ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/type/spi/TypeConfiguration.java b/hibernate-core/src/main/java/org/hibernate/type/spi/TypeConfiguration.java index 5427c8f587..4617ad2290 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/spi/TypeConfiguration.java +++ b/hibernate-core/src/main/java/org/hibernate/type/spi/TypeConfiguration.java @@ -8,6 +8,7 @@ package org.hibernate.type.spi; import java.io.InvalidObjectException; import java.io.Serializable; +import java.sql.Types; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -36,6 +37,7 @@ import org.hibernate.type.Type; import org.hibernate.type.TypeFactory; import org.hibernate.type.TypeResolver; import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptorIndicators; import org.hibernate.type.descriptor.sql.spi.SqlTypeDescriptorRegistry; import org.hibernate.type.internal.TypeConfigurationRegistry; @@ -66,9 +68,9 @@ public class TypeConfiguration implements SessionFactoryObserver, Serializable { private final String uuid = LocalObjectUuidHelper.generateLocalObjectUuid(); private final Scope scope; - private final transient TypeFactory typeFactory; - // things available during both boot and runtime ("active") lifecycle phases + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // things available during both boot and runtime lifecycle phases private final transient JavaTypeDescriptorRegistry javaTypeDescriptorRegistry; private final transient SqlTypeDescriptorRegistry sqlTypeDescriptorRegistry; private final transient BasicTypeRegistry basicTypeRegistry; @@ -78,14 +80,17 @@ public class TypeConfiguration implements SessionFactoryObserver, Serializable { private final transient Map> jdbcToHibernateTypeContributionMap = new HashMap<>(); // temporarily needed to support deprecations + private final transient TypeFactory typeFactory; private final transient TypeResolver typeResolver; public TypeConfiguration() { - this.scope = new Scope(); + this.scope = new Scope( this ); + this.javaTypeDescriptorRegistry = new JavaTypeDescriptorRegistry( this ); this.sqlTypeDescriptorRegistry = new SqlTypeDescriptorRegistry( this ); this.basicTypeRegistry = new BasicTypeRegistry(); + this.typeFactory = new TypeFactory( this ); this.typeResolver = new TypeResolver( this, typeFactory ); @@ -127,6 +132,10 @@ public class TypeConfiguration implements SessionFactoryObserver, Serializable { return Collections.unmodifiableMap( importMap ); } + public SqlTypeDescriptorIndicators getCurrentBaseSqlTypeIndicators() { + return scope.getCurrentBaseSqlTypeIndicators(); + } + public Map> getJdbcToHibernateTypeContributionMap() { return jdbcToHibernateTypeContributionMap; } @@ -271,16 +280,34 @@ public class TypeConfiguration implements SessionFactoryObserver, Serializable { * Each stage or phase is consider a "scope" for the TypeConfiguration. */ private static class Scope implements Serializable { + private final TypeConfiguration typeConfiguration; - // todo (6.0) : consider a proper contract implemented by both SessionFactory (or its metamodel) and boot's MetadataImplementor - // 1) type-related info from MetadataBuildingOptions - // 2) ServiceRegistry private transient MetadataBuildingContext metadataBuildingContext; private transient SessionFactoryImplementor sessionFactory; private String sessionFactoryName; private String sessionFactoryUuid; + private transient SqlTypeDescriptorIndicators currentSqlTypeIndicators = new SqlTypeDescriptorIndicators() { + @Override + public TypeConfiguration getTypeConfiguration() { + return typeConfiguration; + } + + @Override + public int getPreferredSqlTypeCodeForBoolean() { + return Types.BOOLEAN; + } + }; + + public Scope(TypeConfiguration typeConfiguration) { + this.typeConfiguration = typeConfiguration; + } + + public SqlTypeDescriptorIndicators getCurrentBaseSqlTypeIndicators() { + return currentSqlTypeIndicators; + } + public MetadataBuildingContext getMetadataBuildingContext() { if ( metadataBuildingContext == null ) { throw new HibernateException( "TypeConfiguration is not currently scoped to MetadataBuildingContext" );