17
17
import static java .lang .Integer .MAX_VALUE ;
18
18
import static java .lang .String .format ;
19
19
import static java .util .Collections .emptyList ;
20
- import static java .util .Collections .emptySet ;
21
20
import static java .util .Collections .unmodifiableSet ;
22
21
import static java .util .Optional .ofNullable ;
23
22
import static java .util .logging .Level .FINE ;
72
71
import java .util .concurrent .ConcurrentHashMap ;
73
72
import java .util .function .Consumer ;
74
73
import java .util .function .Function ;
74
+ import java .util .function .Supplier ;
75
75
import java .util .logging .Level ;
76
76
import java .util .logging .Logger ;
77
77
@@ -223,9 +223,9 @@ public abstract class BaseEntityService<I extends Comparable<I> & Serializable,
223
223
224
224
private Provider provider = Provider .UNKNOWN ;
225
225
private Database database = Database .UNKNOWN ;
226
- private Set <String > elementCollections = emptySet () ;
227
- private Set <String > manyOrOneToOnes = emptySet () ;
228
- private java .util .function .Predicate <String > oneToManys = field -> false ;
226
+ private Supplier < Set <String >> elementCollections = Collections :: emptySet ;
227
+ private Supplier < Set <String >> manyOrOneToOnes = Collections :: emptySet ;
228
+ private java .util .function .Predicate <String > oneToManys = field -> false ;
229
229
private Validator validator ;
230
230
231
231
@ PersistenceContext
@@ -254,8 +254,8 @@ protected BaseEntityService() {
254
254
protected void initWithEntityManager () {
255
255
provider = Provider .of (getEntityManager ());
256
256
database = Database .of (getEntityManager ());
257
- elementCollections = ELEMENT_COLLECTION_MAPPINGS .computeIfAbsent (entityType , this ::computeElementCollectionMapping );
258
- manyOrOneToOnes = MANY_OR_ONE_TO_ONE_MAPPINGS .computeIfAbsent (entityType , this ::computeManyOrOneToOneMapping );
257
+ elementCollections = () -> ELEMENT_COLLECTION_MAPPINGS .computeIfAbsent (entityType , this ::computeElementCollectionMapping );
258
+ manyOrOneToOnes = () -> MANY_OR_ONE_TO_ONE_MAPPINGS .computeIfAbsent (entityType , this ::computeManyOrOneToOneMapping );
259
259
oneToManys = field -> ONE_TO_MANY_MAPPINGS .computeIfAbsent (entityType , this ::computeOneToManyMapping ).stream ().anyMatch (oneToMany -> field .startsWith (oneToMany + '.' ));
260
260
261
261
if (getValidationMode (getEntityManager ()) == ValidationMode .CALLBACK ) {
@@ -1838,12 +1838,12 @@ private <T extends E> PathResolver buildSelection(PageBuilder<T> pageBuilder, Ab
1838
1838
var orderingContainsAggregatedFields = aggregatedFields .removeAll (pageBuilder .getPage ().getOrdering ().keySet ());
1839
1839
pageBuilder .shouldBuildCountSubquery (true ); // Normally, building of count subquery is skipped for performance, but when there's a custom mapping, we cannot reliably determine if custom criteria is used, so count subquery building cannot be reliably skipped.
1840
1840
pageBuilder .canBuildValueBasedPagingPredicate (getProvider () != HIBERNATE || !orderingContainsAggregatedFields ); // Value based paging cannot be used in Hibernate if ordering contains aggregated fields, because Hibernate may return a cartesian product and apply firstResult/maxResults in memory.
1841
- return new MappedPathResolver (root , paths , ELEMENT_COLLECTION_MAPPINGS .get (entityType ), MANY_OR_ONE_TO_ONE_MAPPINGS .get (entityType ));
1841
+ return new MappedPathResolver (root , paths , elementCollections .get (), manyOrOneToOnes .get ());
1842
1842
}
1843
1843
else if (pageBuilder .getResultType () == entityType ) {
1844
1844
pageBuilder .shouldBuildCountSubquery (mapping != null ); // mapping is empty but not null when getPage(..., QueryBuilder) is used.
1845
1845
pageBuilder .canBuildValueBasedPagingPredicate (mapping == null ); // when mapping is not null, we cannot reliably determine if ordering contains aggregated fields, so value based paging cannot be reliably used.
1846
- return new RootPathResolver (root , ELEMENT_COLLECTION_MAPPINGS .get (entityType ), MANY_OR_ONE_TO_ONE_MAPPINGS .get (entityType ));
1846
+ return new RootPathResolver (root , elementCollections .get (), manyOrOneToOnes .get ());
1847
1847
}
1848
1848
else {
1849
1849
throw new IllegalArgumentException (ERROR_ILLEGAL_MAPPING );
@@ -1889,7 +1889,7 @@ private <T extends E> void buildOrderBy(PageBuilder<T> pageBuilder, CriteriaQuer
1889
1889
private Order buildOrder (Entry <String , Boolean > order , CriteriaBuilder criteriaBuilder , PathResolver pathResolver , boolean reversed ) {
1890
1890
var field = order .getKey ();
1891
1891
1892
- if (oneToManys .test (field ) || elementCollections .contains (field )) {
1892
+ if (oneToManys .test (field ) || elementCollections .get (). contains (field )) {
1893
1893
if (getProvider () == ECLIPSELINK ) {
1894
1894
throw new UnsupportedOperationException (ERROR_UNSUPPORTED_ONETOMANY_ORDERBY_ECLIPSELINK ); // EclipseLink refuses to perform a JOIN when setFirstResult/setMaxResults is used.
1895
1895
}
@@ -1993,7 +1993,7 @@ private <T extends E> List<Predicate> buildPredicates(Map<String, Object> criter
1993
1993
1994
1994
private <T extends E > Predicate buildPredicate (Entry <String , Object > parameter , AbstractQuery <T > query , CriteriaBuilder criteriaBuilder , PathResolver pathResolver , Map <String , Object > parameters ) {
1995
1995
var field = parameter .getKey ();
1996
- var path = pathResolver .get (elementCollections .contains (field ) ? pathResolver .join (field ) : field );
1996
+ var path = pathResolver .get (elementCollections .get (). contains (field ) ? pathResolver .join (field ) : field );
1997
1997
var type = ID .equals (field ) ? identifierType : path .getJavaType ();
1998
1998
return buildTypedPredicate (path , type , field , parameter .getValue (), query , criteriaBuilder , pathResolver , new UncheckedParameterBuilder (field , criteriaBuilder , parameters ));
1999
1999
}
@@ -2016,7 +2016,7 @@ private <T extends E> Predicate buildTypedPredicate(Expression<?> path, Class<?>
2016
2016
else if (value instanceof Criteria <?> criteriaObject ) {
2017
2017
predicate = criteriaObject .build (path , criteriaBuilder , parameterBuilder );
2018
2018
}
2019
- else if (elementCollections .contains (field )) {
2019
+ else if (elementCollections .get (). contains (field )) {
2020
2020
predicate = buildElementCollectionPredicate (alias , path , type , field , value , query , criteriaBuilder , pathResolver , parameterBuilder );
2021
2021
}
2022
2022
else if (value instanceof Iterable || value .getClass ().isArray ()) {
@@ -2088,7 +2088,7 @@ private <T extends E> Predicate buildArrayPredicate(Expression<?> path, Class<?>
2088
2088
throw new UnsupportedOperationException (ERROR_UNSUPPORTED_ONETOMANY_CRITERIA_ECLIPSELINK ); // EclipseLink refuses to perform a JOIN when setFirstResult/setMaxResults is used.
2089
2089
}
2090
2090
2091
- var elementCollectionField = elementCollections .contains (field );
2091
+ var elementCollectionField = elementCollections .get (). contains (field );
2092
2092
Subquery <Long > subquery = null ;
2093
2093
Expression <?> fieldPath ;
2094
2094
@@ -2097,7 +2097,7 @@ private <T extends E> Predicate buildArrayPredicate(Expression<?> path, Class<?>
2097
2097
// Otherwise the main query will return ONLY the matching values while the natural expectation in UI is that they are just all returned.
2098
2098
subquery = query .subquery (Long .class );
2099
2099
Root <E > subqueryRoot = subquery .from (entityType );
2100
- fieldPath = new RootPathResolver (subqueryRoot , elementCollections , manyOrOneToOnes ).get (pathResolver .join (field ));
2100
+ fieldPath = new RootPathResolver (subqueryRoot , elementCollections . get () , manyOrOneToOnes . get () ).get (pathResolver .join (field ));
2101
2101
subquery .select (criteriaBuilder .countDistinct (fieldPath )).where (criteriaBuilder .equal (subqueryRoot .get (ID ), pathResolver .get (ID )));
2102
2102
}
2103
2103
else {
0 commit comments