Skip to content

Commit

Permalink
Make compatible with latest OpenJPA: @ElementCollection/@OnetoOne
Browse files Browse the repository at this point in the history
metadata is apparently only available after startup, so changed
BaseEntityService logic to be lazy fetching
  • Loading branch information
BalusC committed Sep 5, 2024
1 parent c6e2b2e commit 7f5265d
Showing 1 changed file with 13 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import static java.lang.Integer.MAX_VALUE;
import static java.lang.String.format;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptySet;
import static java.util.Collections.unmodifiableSet;
import static java.util.Optional.ofNullable;
import static java.util.logging.Level.FINE;
Expand Down Expand Up @@ -72,6 +71,7 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;

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

private Provider provider = Provider.UNKNOWN;
private Database database = Database.UNKNOWN;
private Set<String> elementCollections = emptySet();
private Set<String> manyOrOneToOnes = emptySet();
private java.util.function.Predicate<String> oneToManys = field -> false;
private Supplier<Set<String>> elementCollections = Collections::emptySet;
private Supplier<Set<String>> manyOrOneToOnes = Collections::emptySet;
private java.util.function.Predicate<String> oneToManys = field -> false;
private Validator validator;

@PersistenceContext
Expand Down Expand Up @@ -254,8 +254,8 @@ protected BaseEntityService() {
protected void initWithEntityManager() {
provider = Provider.of(getEntityManager());
database = Database.of(getEntityManager());
elementCollections = ELEMENT_COLLECTION_MAPPINGS.computeIfAbsent(entityType, this::computeElementCollectionMapping);
manyOrOneToOnes = MANY_OR_ONE_TO_ONE_MAPPINGS.computeIfAbsent(entityType, this::computeManyOrOneToOneMapping);
elementCollections = () -> ELEMENT_COLLECTION_MAPPINGS.computeIfAbsent(entityType, this::computeElementCollectionMapping);
manyOrOneToOnes = () -> MANY_OR_ONE_TO_ONE_MAPPINGS.computeIfAbsent(entityType, this::computeManyOrOneToOneMapping);
oneToManys = field -> ONE_TO_MANY_MAPPINGS.computeIfAbsent(entityType, this::computeOneToManyMapping).stream().anyMatch(oneToMany -> field.startsWith(oneToMany + '.'));

if (getValidationMode(getEntityManager()) == ValidationMode.CALLBACK) {
Expand Down Expand Up @@ -1838,12 +1838,12 @@ private <T extends E> PathResolver buildSelection(PageBuilder<T> pageBuilder, Ab
var orderingContainsAggregatedFields = aggregatedFields.removeAll(pageBuilder.getPage().getOrdering().keySet());
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.
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.
return new MappedPathResolver(root, paths, ELEMENT_COLLECTION_MAPPINGS.get(entityType), MANY_OR_ONE_TO_ONE_MAPPINGS.get(entityType));
return new MappedPathResolver(root, paths, elementCollections.get(), manyOrOneToOnes.get());
}
else if (pageBuilder.getResultType() == entityType) {
pageBuilder.shouldBuildCountSubquery(mapping != null); // mapping is empty but not null when getPage(..., QueryBuilder) is used.
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.
return new RootPathResolver(root, ELEMENT_COLLECTION_MAPPINGS.get(entityType), MANY_OR_ONE_TO_ONE_MAPPINGS.get(entityType));
return new RootPathResolver(root, elementCollections.get(), manyOrOneToOnes.get());
}
else {
throw new IllegalArgumentException(ERROR_ILLEGAL_MAPPING);
Expand Down Expand Up @@ -1889,7 +1889,7 @@ private <T extends E> void buildOrderBy(PageBuilder<T> pageBuilder, CriteriaQuer
private Order buildOrder(Entry<String, Boolean> order, CriteriaBuilder criteriaBuilder, PathResolver pathResolver, boolean reversed) {
var field = order.getKey();

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

private <T extends E> Predicate buildPredicate(Entry<String, Object> parameter, AbstractQuery<T> query, CriteriaBuilder criteriaBuilder, PathResolver pathResolver, Map<String, Object> parameters) {
var field = parameter.getKey();
var path = pathResolver.get(elementCollections.contains(field) ? pathResolver.join(field) : field);
var path = pathResolver.get(elementCollections.get().contains(field) ? pathResolver.join(field) : field);
var type = ID.equals(field) ? identifierType : path.getJavaType();
return buildTypedPredicate(path, type, field, parameter.getValue(), query, criteriaBuilder, pathResolver, new UncheckedParameterBuilder(field, criteriaBuilder, parameters));
}
Expand All @@ -2016,7 +2016,7 @@ private <T extends E> Predicate buildTypedPredicate(Expression<?> path, Class<?>
else if (value instanceof Criteria<?> criteriaObject) {
predicate = criteriaObject.build(path, criteriaBuilder, parameterBuilder);
}
else if (elementCollections.contains(field)) {
else if (elementCollections.get().contains(field)) {
predicate = buildElementCollectionPredicate(alias, path, type, field, value, query, criteriaBuilder, pathResolver, parameterBuilder);
}
else if (value instanceof Iterable || value.getClass().isArray()) {
Expand Down Expand Up @@ -2088,7 +2088,7 @@ private <T extends E> Predicate buildArrayPredicate(Expression<?> path, Class<?>
throw new UnsupportedOperationException(ERROR_UNSUPPORTED_ONETOMANY_CRITERIA_ECLIPSELINK); // EclipseLink refuses to perform a JOIN when setFirstResult/setMaxResults is used.
}

var elementCollectionField = elementCollections.contains(field);
var elementCollectionField = elementCollections.get().contains(field);
Subquery<Long> subquery = null;
Expression<?> fieldPath;

Expand All @@ -2097,7 +2097,7 @@ private <T extends E> Predicate buildArrayPredicate(Expression<?> path, Class<?>
// Otherwise the main query will return ONLY the matching values while the natural expectation in UI is that they are just all returned.
subquery = query.subquery(Long.class);
Root<E> subqueryRoot = subquery.from(entityType);
fieldPath = new RootPathResolver(subqueryRoot, elementCollections, manyOrOneToOnes).get(pathResolver.join(field));
fieldPath = new RootPathResolver(subqueryRoot, elementCollections.get(), manyOrOneToOnes.get()).get(pathResolver.join(field));
subquery.select(criteriaBuilder.countDistinct(fieldPath)).where(criteriaBuilder.equal(subqueryRoot.get(ID), pathResolver.get(ID)));
}
else {
Expand Down

0 comments on commit 7f5265d

Please sign in to comment.