mappings = descriptor.getMappings();
+ for (DatabaseMapping mapping : mappings) {
+ if (!mapping.isLazy() && !isLoaded(entity, mapping.getAttributeName(), mapping)) {
+ load(entity, mapping.getAttributeName(), mapping);
+ }
+ }
+ } else {
+ throw new IllegalArgumentException(ExceptionLocalization.buildMessage(
+ "jpa_persistence_util_non_persistent_class", new Object[] {entity}));
+ }
+ }
/**
- * Determine the load state of an entity belonging to the persistence unit.
- * This method can be used to determine the load state of an entity passed
- * as a reference. An entity is considered loaded if all attributes for
- * which FetchType EAGER has been specified have been loaded. The
- * isLoaded(Object, String) method should be used to determine the load
- * state of an attribute. Not doing so might lead to unintended loading of
- * state.
+ * Load the persistent value of a given persistent attribute
+ * of an entity belonging to the persistence unit and to an
+ * open persistence context.
+ * After this method returns, {@link #isLoaded(Object, String, AbstractSession)}
+ * must return true with the given entity instance and attribute.
*
- * @param entity
- * whose load state is to be determined
- * @return false if the entity has not been loaded, else true.
+ * @param entity entity instance to be loaded
+ * @param attributeName the name of the attribute to be loaded
+ * @param session database session
+ * @throws IllegalArgumentException if the given object is not an instance
+ * of an entity class belonging to the persistence unit
+ */
+ static void load(Object entity, String attributeName, AbstractSession session) {
+ ClassDescriptor descriptor = session.getDescriptor(entity);
+ if (descriptor != null) {
+ DatabaseMapping mapping = descriptor.getMappingForAttributeName(attributeName);
+ if (mapping != null) {
+ load(entity, attributeName, mapping);
+ }
+ } else {
+ throw new IllegalArgumentException(ExceptionLocalization.buildMessage(
+ "jpa_persistence_util_non_persistent_class", new Object[] {entity}));
+ }
+ }
+
+ /**
+ * Load the persistent value of a given persistent attribute
+ * of an entity belonging to the persistence unit with a given mapping.
+ *
+ * @param entity entity instance to be loaded
+ * @param attributeName the name of the attribute to be loaded
+ * @param mapping database mapping metadata of the attribute
+ */
+ private static void load(Object entity, String attributeName, DatabaseMapping mapping) {
+ if (mapping.isForeignReferenceMapping()) {
+ Object value = mapping.getAttributeValueFromObject(entity);
+ IndirectionPolicy policy = ((ForeignReferenceMapping) mapping).getIndirectionPolicy();
+ if (!policy.objectIsInstantiated(value)) {
+ policy.instantiateObject(entity, value);
+ }
+ } else if (entity instanceof FetchGroupTracker tracker) {
+ if (!tracker._persistence_isAttributeFetched(attributeName)) {
+ EntityManagerImpl.processUnfetchedAttribute(tracker, attributeName);
+ }
+ }
+ }
+
+ /**
+ * Determine the load state of an entity belonging to the
+ * persistence unit. This method can be used to determine the
+ * load state of an entity passed as a reference. An entity is
+ * considered loaded if all attributes for which
+ * {@link jakarta.persistence.FetchType#EAGER} has been specified have been loaded.
+ * The {@link #isLoaded(Object, String)} method should be
+ * used to determine the load state of an attribute. Not doing
+ * so might lead to unintended loading of state.
+ *
+ * @param entity entity instance whose load state is to be determined
+ * @param session database session
+ * @return Value of {@code true} if the given entity has been loaded
+ * or {@code false} otherwise.
*/
public static Boolean isLoaded(Object entity, AbstractSession session) {
ClassDescriptor descriptor = session.getDescriptor(entity);
@@ -124,9 +199,7 @@ public static Boolean isLoaded(Object entity, AbstractSession session) {
return null;
}
List mappings = descriptor.getMappings();
- Iterator i = mappings.iterator();
- while (i.hasNext()) {
- DatabaseMapping mapping = i.next();
+ for (DatabaseMapping mapping : mappings) {
if (!mapping.isLazy() && !isLoaded(entity, mapping.getAttributeName(), mapping)) {
return false;
}
@@ -134,17 +207,15 @@ public static Boolean isLoaded(Object entity, AbstractSession session) {
return true;
}
-
/**
- * Determine the load state of a given persistent attribute of an entity
- * belonging to the persistence unit.
+ * Determine the load state of a given persistent attribute
+ * of an entity belonging to the persistence unit.
*
- * @param entity
- * containing the attribute
- * @param attributeName
- * name of attribute whose load state is to be determined
- * @return false if entity's state has not been loaded or if the attribute
- * state has not been loaded, otherwise true
+ * @param entity entity instance containing the attribute
+ * @param attributeName name of attribute whose load state is to be determined
+ * @param session database session
+ * @return Value of {@code true} if the given attribute has been loaded
+ * or {@code false} otherwise.
*/
public static Boolean isLoaded(Object entity, String attributeName, AbstractSession session) {
ClassDescriptor descriptor = session.getDescriptor(entity);
@@ -166,11 +237,15 @@ public static Boolean isLoaded(Object entity, String attributeName, AbstractSess
/**
* Check whether a named attribute on a given entity with a given mapping
* has been loaded.
- *
- * This method will check the valueholder or indirect collection for LAZY
+ * This method will check the value holder or indirect collection for LAZY
* ForeignReferenceMappings to see if has been instantiated and otherwise
* check the fetch group.
*
+ * @param entity entity instance containing the attribute
+ * @param attributeName name of attribute whose load state is to be determined
+ * @param mapping database mapping metadata of the attribute
+ * @return Value of {@code true} if the given attribute has been loaded
+ * or {@code false} otherwise.
*/
public static boolean isLoaded(Object entity, String attributeName, DatabaseMapping mapping) {
if (mapping.isForeignReferenceMapping()) {
@@ -188,6 +263,52 @@ public static boolean isLoaded(Object entity, String attributeName, DatabaseMapp
}
}
+ /**
+ * Check whether the given entity belonging to the persistence
+ * unit and to an open persistence context is an instance of the
+ * given entity class, or false otherwise.
+ * This method may, but is not required to, load the given entity
+ * by side effect.
+ *
+ * @param entity entity instance
+ * @param entityClass an entity class belonging to the persistence unit
+ * @param session database session
+ * @return Value of {@code true} if the given entity is an instance
+ * of the given entity class or {@code false} otherwise.
+ * @throws IllegalArgumentException if the given object is not an instance
+ * of an entity class belonging to the persistence unit
+ */
+ static boolean isInstance(Object entity, Class> entityClass, AbstractSession session) {
+ // Just validate that entity belongs to current PU
+ ClassDescriptor descriptor = session.getDescriptor(entity);
+ if (descriptor == null) {
+ throw new IllegalArgumentException(ExceptionLocalization.buildMessage(
+ "jpa_persistence_util_non_persistent_class", new Object[] {entity}));
+ }
+ return entityClass.isInstance(entity);
+ }
+
+ /**
+ * Return the concrete entity class if the given entity belonging
+ * to the persistence unit and to an open persistence context.
+ * This method may, but is not required to, load the given entity
+ * by side effect.
+ *
+ * @param entity entity instance
+ * @param session database session
+ * @return an entity class belonging to the persistence unit
+ * @throws IllegalArgumentException if the given object is not an instance
+ * of an entity class belonging to the persistence unit
+ */
+ static Class extends T> getClass(T entity, AbstractSession session) {
+ ClassDescriptor descriptor = session.getDescriptor(entity);
+ if (descriptor == null) {
+ throw new IllegalArgumentException(ExceptionLocalization.buildMessage(
+ "jpa_persistence_util_non_persistent_class", new Object[] {entity}));
+ }
+ return descriptor.getJavaClass();
+ }
+
/**
* Will return an instance of the Factory. Should only be called by
* EclipseLink.
@@ -624,25 +745,21 @@ public boolean isLoaded(Object entity) {
return delegate.isLoaded(entity);
}
- // TODO-API-3.2
@Override
public void load(Object entity, String attributeName) {
delegate.load(entity, attributeName);
}
- // TODO-API-3.2
@Override
public void load(E entity, Attribute super E, ?> attribute) {
delegate.load(entity, attribute);
}
- // TODO-API-3.2
@Override
public void load(Object entity) {
delegate.load(entity);
}
- // TODO-API-3.2
@Override
public boolean isInstance(Object entity, Class> entityClass) {
return delegate.isInstance(entity, entityClass);
@@ -653,7 +770,6 @@ public String getName() {
return delegate.getName();
}
- // TODO-API-3.2
@Override
public Class extends T> getClass(T entity) {
return delegate.getClass(entity);
diff --git a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/AbstractQueryImpl.java b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/AbstractQueryImpl.java
index 3b613d0fc2c..eba69c1d082 100644
--- a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/AbstractQueryImpl.java
+++ b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/AbstractQueryImpl.java
@@ -29,6 +29,7 @@
import jakarta.persistence.criteria.AbstractQuery;
import jakarta.persistence.criteria.Expression;
+import jakarta.persistence.criteria.ParameterExpression;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.metamodel.EntityType;
@@ -72,13 +73,28 @@ public AbstractQueryImpl(Metamodel metamodel, ResultType queryResult, CriteriaBu
this.baseExpression = new ExpressionBuilder();
}
+ // Allows complete copy of CommonAbstractCriteriaImpl. Required for cast implementation and shall remain pkg private.
+ AbstractQueryImpl(Metamodel metamodel, Expression where, CriteriaBuilderImpl queryBuilder,
+ Class queryType, Set> parameters,
+ ResultType queryResult, boolean distinct, Predicate havingClause,List> groupBy,
+ Set> roots, org.eclipse.persistence.expressions.Expression baseExpression) {
+ super(metamodel, where, queryBuilder, queryType, parameters);
+ this.queryResult = queryResult;
+ this.distinct = distinct;
+ this.havingClause = havingClause;
+ this.groupBy = groupBy;
+ this.roots = roots;
+ this.baseExpression = baseExpression;
+ }
+
/**
* Specify the expressions that are used to form groups over
* the query results.
* Replaces the previous specified grouping expressions, if any.
* If no grouping expressions are specified, any previously
* added grouping expressions are simply removed.
- * @param grouping list of zero or more grouping expressions
+ *
+ * @param grouping list of zero or more grouping expressions
* @return the modified query
*/
@Override
diff --git a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CommonAbstractCriteriaImpl.java b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CommonAbstractCriteriaImpl.java
index 3492dfb1550..ab081351613 100644
--- a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CommonAbstractCriteriaImpl.java
+++ b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CommonAbstractCriteriaImpl.java
@@ -71,6 +71,16 @@ public CommonAbstractCriteriaImpl(Metamodel metamodel, CriteriaBuilderImpl query
this.queryType = resultType;
}
+ // Allows complete copy of CommonAbstractCriteriaImpl. Required for cast implementation and shall remain pkg private.
+ CommonAbstractCriteriaImpl(Metamodel metamodel, Expression where, CriteriaBuilderImpl queryBuilder,
+ Class queryType, Set> parameters) {
+ this.metamodel = metamodel;
+ this.where = where;
+ this.queryBuilder = queryBuilder;
+ this.queryType = queryType;
+ this.parameters = parameters;
+ }
+
/**
* Return the predicate that corresponds to the where clause restriction(s).
*
diff --git a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CriteriaQueryImpl.java b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CriteriaQueryImpl.java
index 02e455c7016..462fe1e7e86 100644
--- a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CriteriaQueryImpl.java
+++ b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CriteriaQueryImpl.java
@@ -497,8 +497,19 @@ protected ReadAllQuery createCompoundQuery(boolean toReportQuery) {
}
if (this.queryResult.equals(ResultType.PARTIAL)) {
+ ReadAllQuery raq;
// TODO: allow force of ReportQuery creation for usage in UNION
- ReadAllQuery raq = new ReadAllQuery(this.queryType);
+ // TODO: In progress, code is not working and tested !!!
+ // See testUnionWithMultiselectEntityParametersInSelection TODO in UnionCriteriaQueryTest
+ if (toReportQuery) {
+ //raq = createReportQuery(this.queryType);
+ raq = createReportQueryWithItem(this.queryType);
+ } else {
+ raq = new ReadAllQuery(this.queryType);
+ }
+ // TODO: double check whether this may be avoided
+ raq.dontMaintainCache();
+ // TODO: ROOTS?
for (Selection selection : this.selection.getCompoundSelectionItems()) {
raq.addPartialAttribute(((SelectionImpl) selection).currentNode);
}
diff --git a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/SubQueryImpl.java b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/SubQueryImpl.java
index b56910b883f..2762f62130a 100644
--- a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/SubQueryImpl.java
+++ b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/SubQueryImpl.java
@@ -40,7 +40,6 @@
import jakarta.persistence.criteria.Subquery;
import jakarta.persistence.metamodel.Metamodel;
import jakarta.persistence.metamodel.Type.PersistenceType;
-
import org.eclipse.persistence.expressions.ExpressionBuilder;
import org.eclipse.persistence.internal.expressions.ConstantExpression;
import org.eclipse.persistence.internal.expressions.SubSelectExpression;
@@ -93,13 +92,33 @@ public SubQueryImpl(Metamodel metamodel, Class result, CriteriaBuilderImpl qu
this.parent = parent;
}
- /**
- * Specify the item that is to be returned in the query result.
- * Replaces the previously specified selection, if any.
- * @param selection selection specifying the item that
- * is to be returned in the query result
- * @return the modified query
- */
+ // Allows complete copy of CommonAbstractCriteriaImpl. Required for cast implementation and shall remain private.
+ private SubQueryImpl(Metamodel metamodel, Expression where, CriteriaBuilderImpl queryBuilder,
+ Class queryType, Set> parameters,
+ ResultType queryResult, boolean distinct, Predicate havingClause,List> groupBy,
+ Set> roots, org.eclipse.persistence.expressions.Expression baseExpression,
+ SelectionImpl> selection,SubSelectExpression currentNode, String alias, ReportQuery subQuery,
+ Set> correlatedJoins, CommonAbstractCriteria parent, Set processedJoins,
+ Set correlations) {
+ super(metamodel, where, queryBuilder, queryType, parameters,
+ queryResult, distinct, havingClause, groupBy, roots, baseExpression);
+ this.selection = selection;
+ this.currentNode = currentNode;
+ this.alias = alias;
+ this.subQuery = subQuery;
+ this.correlatedJoins = correlatedJoins;
+ this.parent = parent;
+ this.processedJoins = processedJoins;
+ this.correlations = correlations;
+ }
+
+ /**
+ * Specify the item that is to be returned in the query result.
+ * Replaces the previously specified selection, if any.
+ * @param selection selection specifying the item that
+ * is to be returned in the query result
+ * @return the modified query
+ */
@Override
public Subquery select(Expression selection) {
findRootAndParameters(selection);
@@ -436,6 +455,15 @@ public Expression as(Class type) {
return (Expression) this;
}
+ @Override
+ public Expression cast(Class aClass) {
+ // JPA spec: New instance with provided Java type
+ return new SubQueryImpl<>(
+ metamodel, where, queryBuilder, aClass, parameters,
+ queryResult, distinct, havingClause, groupBy, roots, baseExpression,
+ selection, currentNode, alias, subQuery, correlatedJoins, parent, processedJoins, correlations);
+ }
+
@Override
public Predicate in(Object... values) {
List> list = new ArrayList<>();
@@ -674,10 +702,4 @@ public DatabaseQuery getDatabaseQuery() {
return this.subQuery;
}
- // TODO-API-3.2
- @Override
- public Expression cast(Class aClass) {
- throw new UnsupportedOperationException("Jakarta Persistence 3.2 API was not implemented yet");
- }
-
}