Skip to content

Commit c73baa4

Browse files
committed
HSEARCH-4869 Avoid most uses of EntityPersister
1 parent d9108a6 commit c73baa4

19 files changed

+190
-228
lines changed

build/config/src/main/resources/forbidden-public.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ java.time.ZonedDateTime#parse(java.lang.CharSequence, java.time.format.DateTimeF
6363
@defaultMessage Avoid using Hibernate ORM internals
6464
org.hibernate.internal.**
6565
org.hibernate.**.internal.**
66+
org.hibernate.persister.** @ Prefer EntityMappingType to the implicitly internal EntityPersister and related classes; see https://hibernate.zulipchat.com/#narrow/stream/132094-hibernate-orm-dev/topic/persister.20and.20internal
6667

6768
################################################################################################################
6869
@defaultMessage Favor EntityManager methods over their Session equivalent

mapper/orm-batch-jsr352/core/src/main/java/org/hibernate/search/batch/jsr352/core/massindexing/util/impl/CompositeIdOrder.java

Lines changed: 35 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@
77
package org.hibernate.search.batch.jsr352.core.massindexing.util.impl;
88

99
import java.util.ArrayList;
10-
import java.util.Arrays;
11-
import java.util.Comparator;
1210
import java.util.List;
13-
import java.util.ListIterator;
1411
import java.util.function.BiFunction;
1512
import jakarta.persistence.EmbeddedId;
1613
import jakarta.persistence.IdClass;
@@ -20,7 +17,8 @@
2017
import jakarta.persistence.criteria.Predicate;
2118
import jakarta.persistence.criteria.Root;
2219

23-
import org.hibernate.type.ComponentType;
20+
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
21+
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
2422

2523
/**
2624
* Order over multiple ID attributes.
@@ -48,32 +46,12 @@
4846
*/
4947
public class CompositeIdOrder implements IdOrder {
5048

51-
private final ComponentType componentType;
49+
private final EntityIdentifierMapping mapping;
50+
private final EmbeddableMappingType mappingType;
5251

53-
private final List<String> propertyPaths;
54-
55-
private final List<Integer> propertyIndices;
56-
57-
public CompositeIdOrder(String componentPath, ComponentType componentType) {
58-
super();
59-
this.componentType = componentType;
60-
61-
// Initialize with relative paths, but prepend a prefix below
62-
this.propertyPaths = new ArrayList<>( Arrays.asList( componentType.getPropertyNames() ) );
63-
this.propertyPaths.sort( Comparator.naturalOrder() );
64-
65-
String pathPrefix = componentPath == null ? "" : componentPath + ".";
66-
this.propertyIndices = new ArrayList<>( propertyPaths.size() );
67-
ListIterator<String> iterator = this.propertyPaths.listIterator();
68-
while ( iterator.hasNext() ) {
69-
String propertyName = iterator.next();
70-
71-
// We need the relative path of the property here
72-
propertyIndices.add( componentType.getPropertyIndex( propertyName ) );
73-
74-
// Prepend the path prefix to each property; we will only use absolute path from now on
75-
iterator.set( pathPrefix + propertyName );
76-
}
52+
public CompositeIdOrder(EntityIdentifierMapping mapping, EmbeddableMappingType mappingType) {
53+
this.mapping = mapping;
54+
this.mappingType = mappingType;
7755
}
7856

7957
@Override
@@ -106,54 +84,51 @@ public Predicate idLesser(CriteriaBuilder builder, Root<?> root, Object idObj) {
10684

10785
@Override
10886
public void addAscOrder(CriteriaBuilder builder, CriteriaQuery<?> criteria, Root<?> root) {
109-
ArrayList<Order> orders = new ArrayList<>( propertyPaths.size() );
110-
for ( String path : propertyPaths ) {
111-
orders.add( builder.asc( root.get( path ) ) );
112-
}
87+
ArrayList<Order> orders = new ArrayList<>();
88+
mapping.forEachSelectable( (i, selectable) ->
89+
orders.add( builder.asc( root.get( selectable.getSelectablePath().getFullPath() ) ) ) );
11390
criteria.orderBy( orders );
11491
}
11592

11693
private Predicate restrictLexicographically(BiFunction<String, Object, Predicate> strictOperator,
11794
CriteriaBuilder builder, Root<?> root, Object idObj, boolean orEquals) {
118-
int propertyPathsSize = propertyPaths.size();
119-
int expressionsInOr = propertyPathsSize + ( orEquals ? 1 : 0 );
95+
Object[] selectableValues = mappingType.getValues( idObj );
96+
int selectablesSize = selectableValues.length;
12097

121-
Predicate[] or = new Predicate[expressionsInOr];
98+
List<Predicate> or = new ArrayList<>();
12299

123-
for ( int i = 0; i < propertyPathsSize; i++ ) {
100+
mapping.forEachSelectable( (i, selectable) -> {
124101
// Group expressions together in a single conjunction (A and B and C...).
125102
Predicate[] and = new Predicate[i + 1];
126-
int j = 0;
127-
for ( ; j < and.length - 1; j++ ) {
128-
// The first N-1 expressions have symbol `=`
129-
String path = propertyPaths.get( j );
130-
Object val = getPropertyValue( idObj, j );
131-
and[j] = builder.equal( root.get( path ), val );
132-
}
103+
104+
mapping.forEachSelectable( (j, previousSelectable) -> {
105+
if ( j < i ) {
106+
// The first N-1 expressions have symbol `=`
107+
String path = previousSelectable.getSelectablePath().getFullPath();
108+
Object val = selectableValues[j];
109+
and[j] = builder.equal( root.get( path ), val );
110+
}
111+
} );
133112
// The last expression has whatever symbol is defined by "strictOperator"
134-
String path = propertyPaths.get( j );
135-
Object val = getPropertyValue( idObj, j );
136-
and[j] = strictOperator.apply( path, val );
113+
String path = selectable.getSelectablePath().getFullPath();
114+
Object val = selectableValues[i];
115+
and[i] = strictOperator.apply( path, val );
137116

138-
or[i] = builder.and( and );
139-
}
117+
or.add( builder.and( and ) );
118+
} );
140119

141120
if ( orEquals ) {
142-
Predicate[] and = new Predicate[propertyPathsSize];
143-
for ( int i = 0; i < propertyPathsSize; i++ ) {
144-
String path = propertyPaths.get( i );
145-
Object val = getPropertyValue( idObj, i );
121+
Predicate[] and = new Predicate[selectablesSize];
122+
mapping.forEachSelectable( (i, previousSelectable) -> {
123+
String path = previousSelectable.getSelectablePath().getFullPath();
124+
Object val = selectableValues[i];
146125
and[i] = builder.equal( root.get( path ), val );
147-
}
148-
or[or.length - 1] = builder.and( and );
126+
} );
127+
or.add( builder.and( and ) );
149128
}
150129

151130
// Group the disjunction of multiple expressions (X or Y or Z...).
152-
return builder.or( or );
131+
return builder.or( or.toArray( new Predicate[0] ) );
153132
}
154133

155-
private Object getPropertyValue(Object obj, int ourIndex) {
156-
int theirIndex = propertyIndices.get( ourIndex );
157-
return componentType.getPropertyValue( obj, theirIndex );
158-
}
159134
}

mapper/orm-batch-jsr352/core/src/main/java/org/hibernate/search/batch/jsr352/core/massindexing/util/impl/PersistenceUtil.java

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@
1919
import org.hibernate.StatelessSessionBuilder;
2020
import org.hibernate.engine.spi.SessionFactoryImplementor;
2121
import org.hibernate.metamodel.MappingMetamodel;
22-
import org.hibernate.persister.entity.EntityPersister;
22+
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
23+
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
24+
import org.hibernate.metamodel.mapping.EntityMappingType;
2325
import org.hibernate.search.batch.jsr352.core.massindexing.step.impl.IndexScope;
2426
import org.hibernate.search.util.common.impl.StringHelper;
25-
import org.hibernate.type.ComponentType;
26-
import org.hibernate.type.Type;
2727

2828
/**
2929
* Internal utility class for persistence usage.
@@ -103,20 +103,19 @@ public static List<EntityTypeDescriptor> createDescriptors(EntityManagerFactory
103103
}
104104

105105
private static <T> EntityTypeDescriptor createDescriptor(MappingMetamodel metamodel, Class<T> type) {
106-
EntityPersister entityPersister = metamodel.findEntityDescriptor( type );
107-
IdOrder idOrder = createIdOrder( entityPersister );
106+
EntityMappingType entityMappingType = metamodel.findEntityDescriptor( type );
107+
IdOrder idOrder = createIdOrder( entityMappingType );
108108
return new EntityTypeDescriptor( type, idOrder );
109109
}
110110

111-
private static IdOrder createIdOrder(EntityPersister entityPersister) {
112-
final String identifierPropertyName = entityPersister.getIdentifierPropertyName();
113-
final Type identifierType = entityPersister.getIdentifierType();
114-
if ( identifierType instanceof ComponentType ) {
115-
final ComponentType componentType = (ComponentType) identifierType;
116-
return new CompositeIdOrder( identifierPropertyName, componentType );
111+
private static IdOrder createIdOrder(EntityMappingType entityMappingType) {
112+
EntityIdentifierMapping identifierMapping = entityMappingType.getIdentifierMapping();
113+
if ( identifierMapping.getPartMappingType() instanceof EmbeddableMappingType ) {
114+
return new CompositeIdOrder( identifierMapping,
115+
(EmbeddableMappingType) identifierMapping.getPartMappingType() );
117116
}
118117
else {
119-
return new SingularIdOrder( identifierPropertyName );
118+
return new SingularIdOrder( identifierMapping.getAttributeName() );
120119
}
121120
}
122121

mapper/orm/src/main/java/org/hibernate/search/mapper/orm/common/impl/HibernateOrmUtils.java

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,14 @@
1616
import jakarta.persistence.EntityManager;
1717
import jakarta.persistence.EntityManagerFactory;
1818

19-
import org.hibernate.AssertionFailure;
2019
import org.hibernate.Session;
2120
import org.hibernate.engine.spi.SessionFactoryImplementor;
2221
import org.hibernate.engine.spi.SessionImplementor;
2322
import org.hibernate.mapping.Property;
2423
import org.hibernate.metamodel.MappingMetamodel;
2524
import org.hibernate.metamodel.mapping.EntityMappingType;
26-
import org.hibernate.persister.entity.EntityPersister;
2725
import org.hibernate.search.mapper.orm.logging.impl.Log;
26+
import org.hibernate.search.util.common.AssertionFailure;
2827
import org.hibernate.search.util.common.annotation.impl.SuppressForbiddenApis;
2928
import org.hibernate.search.util.common.logging.impl.LoggerFactory;
3029
import org.hibernate.service.Service;
@@ -66,50 +65,34 @@ public static SessionImplementor toSessionImplementor(EntityManager entityManage
6665
}
6766
}
6867

69-
private static boolean isSuperTypeOf(EntityPersister type1, EntityPersister type2) {
70-
return type1.isSubclassEntityName( type2.getEntityName() );
68+
private static boolean isSuperTypeOf(EntityMappingType type1, EntityMappingType type2) {
69+
return type1.getSubclassEntityNames().contains( type2.getEntityName() );
7170
}
7271

73-
public static EntityPersister toRootEntityType(SessionFactoryImplementor sessionFactory,
74-
EntityPersister entityType) {
75-
/*
76-
* We need to rely on Hibernate ORM's SPIs: this is complex stuff.
77-
* For example there may be class hierarchies such as A > B > C
78-
* where A and C are entity types and B is a mapped superclass.
79-
* So we need to exclude non-entity types, and for that we need the Hibernate ORM metamodel.
80-
*/
81-
MappingMetamodel metamodel = sessionFactory.getMappingMetamodel();
82-
String rootEntityName = entityType.getRootEntityName();
83-
return metamodel.getEntityDescriptor( rootEntityName );
84-
}
85-
86-
public static EntityPersister toMostSpecificCommonEntitySuperType(EntityPersister type1, EntityPersister type2) {
72+
public static EntityMappingType toMostSpecificCommonEntitySuperType(EntityMappingType type1, EntityMappingType type2) {
8773
/*
8874
* We need to rely on Hibernate ORM's SPIs: this is complex stuff.
8975
* For example there may be class hierarchies such as A > B > C
9076
* where A and C are entity types and B is a mapped superclass.
9177
* So even if we know the two types have a common superclass,
9278
* we need to skip non-entity superclasses, and for that we need the Hibernate ORM metamodel.
9379
*/
94-
EntityPersister superTypeCandidate = type1;
80+
EntityMappingType superTypeCandidate = type1;
9581
while ( superTypeCandidate != null && !isSuperTypeOf( superTypeCandidate, type2 ) ) {
96-
EntityMappingType superSuperType = superTypeCandidate.getSuperMappingType();
97-
superTypeCandidate = superSuperType == null ? null : superSuperType.getEntityPersister();
82+
superTypeCandidate = superTypeCandidate.getSuperMappingType();
9883
}
9984
if ( superTypeCandidate == null ) {
10085
throw new AssertionFailure(
10186
"Cannot find a common entity supertype for " + type1.getEntityName()
10287
+ " and " + type2.getEntityName() + "."
103-
+ " There is a bug in Hibernate Search, please report it."
10488
);
10589
}
10690
return superTypeCandidate;
10791
}
10892

10993
public static boolean targetsAllConcreteSubTypes(SessionFactoryImplementor sessionFactory,
110-
EntityPersister parentType, Collection<?> targetConcreteSubTypes) {
111-
@SuppressWarnings("unchecked")
112-
Set<String> subClassEntityNames = parentType.getEntityMetamodel().getSubclassEntityNames();
94+
EntityMappingType parentType, Collection<?> targetConcreteSubTypes) {
95+
Set<String> subClassEntityNames = parentType.getSubclassEntityNames();
11396
// Quick check to return true immediately if all subtypes are concrete
11497
if ( subClassEntityNames.size() == targetConcreteSubTypes.size() ) {
11598
return true;
@@ -118,7 +101,8 @@ public static boolean targetsAllConcreteSubTypes(SessionFactoryImplementor sessi
118101
MappingMetamodel metamodel = sessionFactory.getMappingMetamodel();
119102
int concreteSubTypesCount = 0;
120103
for ( String subClassEntityName : subClassEntityNames ) {
121-
if ( !metamodel.getEntityDescriptor( subClassEntityName ).isAbstract() ) {
104+
EntityMappingType subclassType = metamodel.getEntityDescriptor( subClassEntityName );
105+
if ( !subclassType.isAbstract() ) {
122106
++concreteSubTypesCount;
123107
}
124108
}
@@ -130,7 +114,7 @@ public static <T extends Service> T getServiceOrFail(ServiceRegistry serviceRegi
130114
Class<T> serviceClass) {
131115
T service = serviceRegistry.getService( serviceClass );
132116
if ( service == null ) {
133-
throw new org.hibernate.search.util.common.AssertionFailure( "A required service was missing. Missing service: " + serviceClass );
117+
throw new AssertionFailure( "A required service was missing. Missing service: " + serviceClass );
134118
}
135119
return service;
136120
}

mapper/orm/src/main/java/org/hibernate/search/mapper/orm/event/impl/HibernateSearchEventListener.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,13 @@
3535
import org.hibernate.event.spi.PostInsertEventListener;
3636
import org.hibernate.event.spi.PostUpdateEvent;
3737
import org.hibernate.event.spi.PostUpdateEventListener;
38+
import org.hibernate.metamodel.mapping.EntityMappingType;
3839
import org.hibernate.persister.entity.EntityPersister;
3940
import org.hibernate.search.mapper.orm.common.impl.HibernateOrmUtils;
4041
import org.hibernate.search.mapper.orm.logging.impl.Log;
4142
import org.hibernate.search.mapper.pojo.work.spi.PojoIndexingPlan;
4243
import org.hibernate.search.mapper.pojo.work.spi.PojoTypeIndexingPlan;
44+
import org.hibernate.search.util.common.annotation.impl.SuppressForbiddenApis;
4345
import org.hibernate.search.util.common.logging.impl.LoggerFactory;
4446

4547
/**
@@ -289,8 +291,8 @@ private PojoIndexingPlan getCurrentIndexingPlanIfExisting(SessionImplementor ses
289291
return contextProvider.currentIndexingPlanIfExisting( sessionImplementor );
290292
}
291293

292-
private HibernateOrmListenerTypeContext getTypeContextOrNull(EntityPersister entityPersister) {
293-
String entityName = entityPersister.getEntityName();
294+
private HibernateOrmListenerTypeContext getTypeContextOrNull(EntityMappingType entityMappingType) {
295+
String entityName = entityMappingType.getEntityName();
294296
return contextProvider.typeContextProvider().byHibernateOrmEntityName().getOrNull( entityName );
295297
}
296298

@@ -362,7 +364,7 @@ private void processCollectionEvent(AbstractCollectionEvent event) {
362364
* Required since Hibernate ORM 4.3
363365
*/
364366
@Override
365-
@SuppressWarnings("deprecation") // Deprecated but abstract, so we have to implement it...
367+
@SuppressForbiddenApis(reason = "We are forced to implement this method and it requires accepting an EntityPersister")
366368
public boolean requiresPostCommitHandling(EntityPersister persister) {
367369
// TODO Tests seem to pass using _false_ but we might be able to take
368370
// advantage of this new hook?

mapper/orm/src/main/java/org/hibernate/search/mapper/orm/loading/impl/AbstractHibernateOrmLoadingStrategy.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import java.util.Set;
1414

1515
import org.hibernate.engine.spi.SessionFactoryImplementor;
16-
import org.hibernate.persister.entity.EntityPersister;
16+
import org.hibernate.metamodel.mapping.EntityMappingType;
1717
import org.hibernate.search.mapper.orm.common.impl.HibernateOrmUtils;
1818
import org.hibernate.search.mapper.orm.massindexing.impl.ConditionalExpression;
1919
import org.hibernate.search.util.common.AssertionFailure;
@@ -22,21 +22,21 @@ public abstract class AbstractHibernateOrmLoadingStrategy<E, I>
2222
implements HibernateOrmEntityLoadingStrategy<E, I> {
2323

2424
private final SessionFactoryImplementor sessionFactory;
25-
private final EntityPersister rootEntityPersister;
25+
private final EntityMappingType rootEntityMappingType;
2626
private final TypeQueryFactory<E, I> queryFactory;
2727

2828
AbstractHibernateOrmLoadingStrategy(SessionFactoryImplementor sessionFactory,
29-
EntityPersister rootEntityPersister, TypeQueryFactory<E, I> queryFactory) {
29+
EntityMappingType rootEntityMappingType, TypeQueryFactory<E, I> queryFactory) {
3030
this.sessionFactory = sessionFactory;
31-
this.rootEntityPersister = rootEntityPersister;
31+
this.rootEntityMappingType = rootEntityMappingType;
3232
this.queryFactory = queryFactory;
3333
}
3434

3535
@Override
3636
public HibernateOrmQueryLoader<E, I> createQueryLoader(
3737
List<LoadingTypeContext<? extends E>> typeContexts, Optional<ConditionalExpression> conditionalExpression) {
3838
Set<Class<? extends E>> includedTypesFilter;
39-
if ( HibernateOrmUtils.targetsAllConcreteSubTypes( sessionFactory, rootEntityPersister, typeContexts ) ) {
39+
if ( HibernateOrmUtils.targetsAllConcreteSubTypes( sessionFactory, rootEntityMappingType, typeContexts ) ) {
4040
// All concrete types are included, no need to filter by type.
4141
includedTypesFilter = Collections.emptySet();
4242
}
@@ -52,9 +52,9 @@ public HibernateOrmQueryLoader<E, I> createQueryLoader(
5252
throw new AssertionFailure( "conditional expression is always defined on a single type" );
5353
}
5454

55-
EntityPersister entityPersister = typeContexts.get( 0 ).entityPersister();
55+
EntityMappingType entityMappingType = typeContexts.get( 0 ).entityMappingType();
5656
return new HibernateOrmQueryLoader<>(
57-
queryFactory, entityPersister, includedTypesFilter, conditionalExpression.get() );
57+
queryFactory, entityMappingType, includedTypesFilter, conditionalExpression.get() );
5858
}
5959
return new HibernateOrmQueryLoader<>( queryFactory, includedTypesFilter );
6060
}

0 commit comments

Comments
 (0)