Skip to content

Commit 7f5265d

Browse files
committed
Make compatible with latest OpenJPA: @ElementCollection/@OnetoOne
metadata is apparently only available after startup, so changed BaseEntityService logic to be lazy fetching
1 parent c6e2b2e commit 7f5265d

File tree

1 file changed

+13
-13
lines changed

1 file changed

+13
-13
lines changed

src/main/java/org/omnifaces/persistence/service/BaseEntityService.java

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import static java.lang.Integer.MAX_VALUE;
1818
import static java.lang.String.format;
1919
import static java.util.Collections.emptyList;
20-
import static java.util.Collections.emptySet;
2120
import static java.util.Collections.unmodifiableSet;
2221
import static java.util.Optional.ofNullable;
2322
import static java.util.logging.Level.FINE;
@@ -72,6 +71,7 @@
7271
import java.util.concurrent.ConcurrentHashMap;
7372
import java.util.function.Consumer;
7473
import java.util.function.Function;
74+
import java.util.function.Supplier;
7575
import java.util.logging.Level;
7676
import java.util.logging.Logger;
7777

@@ -223,9 +223,9 @@ public abstract class BaseEntityService<I extends Comparable<I> & Serializable,
223223

224224
private Provider provider = Provider.UNKNOWN;
225225
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;
229229
private Validator validator;
230230

231231
@PersistenceContext
@@ -254,8 +254,8 @@ protected BaseEntityService() {
254254
protected void initWithEntityManager() {
255255
provider = Provider.of(getEntityManager());
256256
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);
259259
oneToManys = field -> ONE_TO_MANY_MAPPINGS.computeIfAbsent(entityType, this::computeOneToManyMapping).stream().anyMatch(oneToMany -> field.startsWith(oneToMany + '.'));
260260

261261
if (getValidationMode(getEntityManager()) == ValidationMode.CALLBACK) {
@@ -1838,12 +1838,12 @@ private <T extends E> PathResolver buildSelection(PageBuilder<T> pageBuilder, Ab
18381838
var orderingContainsAggregatedFields = aggregatedFields.removeAll(pageBuilder.getPage().getOrdering().keySet());
18391839
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.
18401840
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());
18421842
}
18431843
else if (pageBuilder.getResultType() == entityType) {
18441844
pageBuilder.shouldBuildCountSubquery(mapping != null); // mapping is empty but not null when getPage(..., QueryBuilder) is used.
18451845
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());
18471847
}
18481848
else {
18491849
throw new IllegalArgumentException(ERROR_ILLEGAL_MAPPING);
@@ -1889,7 +1889,7 @@ private <T extends E> void buildOrderBy(PageBuilder<T> pageBuilder, CriteriaQuer
18891889
private Order buildOrder(Entry<String, Boolean> order, CriteriaBuilder criteriaBuilder, PathResolver pathResolver, boolean reversed) {
18901890
var field = order.getKey();
18911891

1892-
if (oneToManys.test(field) || elementCollections.contains(field)) {
1892+
if (oneToManys.test(field) || elementCollections.get().contains(field)) {
18931893
if (getProvider() == ECLIPSELINK) {
18941894
throw new UnsupportedOperationException(ERROR_UNSUPPORTED_ONETOMANY_ORDERBY_ECLIPSELINK); // EclipseLink refuses to perform a JOIN when setFirstResult/setMaxResults is used.
18951895
}
@@ -1993,7 +1993,7 @@ private <T extends E> List<Predicate> buildPredicates(Map<String, Object> criter
19931993

19941994
private <T extends E> Predicate buildPredicate(Entry<String, Object> parameter, AbstractQuery<T> query, CriteriaBuilder criteriaBuilder, PathResolver pathResolver, Map<String, Object> parameters) {
19951995
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);
19971997
var type = ID.equals(field) ? identifierType : path.getJavaType();
19981998
return buildTypedPredicate(path, type, field, parameter.getValue(), query, criteriaBuilder, pathResolver, new UncheckedParameterBuilder(field, criteriaBuilder, parameters));
19991999
}
@@ -2016,7 +2016,7 @@ private <T extends E> Predicate buildTypedPredicate(Expression<?> path, Class<?>
20162016
else if (value instanceof Criteria<?> criteriaObject) {
20172017
predicate = criteriaObject.build(path, criteriaBuilder, parameterBuilder);
20182018
}
2019-
else if (elementCollections.contains(field)) {
2019+
else if (elementCollections.get().contains(field)) {
20202020
predicate = buildElementCollectionPredicate(alias, path, type, field, value, query, criteriaBuilder, pathResolver, parameterBuilder);
20212021
}
20222022
else if (value instanceof Iterable || value.getClass().isArray()) {
@@ -2088,7 +2088,7 @@ private <T extends E> Predicate buildArrayPredicate(Expression<?> path, Class<?>
20882088
throw new UnsupportedOperationException(ERROR_UNSUPPORTED_ONETOMANY_CRITERIA_ECLIPSELINK); // EclipseLink refuses to perform a JOIN when setFirstResult/setMaxResults is used.
20892089
}
20902090

2091-
var elementCollectionField = elementCollections.contains(field);
2091+
var elementCollectionField = elementCollections.get().contains(field);
20922092
Subquery<Long> subquery = null;
20932093
Expression<?> fieldPath;
20942094

@@ -2097,7 +2097,7 @@ private <T extends E> Predicate buildArrayPredicate(Expression<?> path, Class<?>
20972097
// Otherwise the main query will return ONLY the matching values while the natural expectation in UI is that they are just all returned.
20982098
subquery = query.subquery(Long.class);
20992099
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));
21012101
subquery.select(criteriaBuilder.countDistinct(fieldPath)).where(criteriaBuilder.equal(subqueryRoot.get(ID), pathResolver.get(ID)));
21022102
}
21032103
else {

0 commit comments

Comments
 (0)