diff --git a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/localization/i18n/ExceptionLocalizationResource.java b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/localization/i18n/ExceptionLocalizationResource.java index 4a87f900d72..28e799a007d 100644 --- a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/localization/i18n/ExceptionLocalizationResource.java +++ b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/localization/i18n/ExceptionLocalizationResource.java @@ -254,7 +254,6 @@ public class ExceptionLocalizationResource extends ListResourceBundle { { "getpersistenceunitutil_called_on_closed_emf", "getPersistenceUnitUtil() was called on a closed EntityManagerFactory."}, { "named_entity_graph_exists", "NamedEntityGraph with name {0} found on {1} already exists in this persistence unit."}, { "cannot_get_from_non_correlated_query", "getCorrelationParent() called on a from-clause that was not obtained through correlation." }, - { "multiple_keys_in_entity", "Cannot add join of {0} to {1} because target class contains multiple attributes of source type"}, { "no_key_in_entity", "Cannot add join of {0} to {1} because target class is missing attribute of source type"}, { "RIGHT_JOIN_NOT_SUPPORTED", "Right join is not supported"}, { "wrap_convert_exception", "An exception occurred while calling {0} on converter class {1} with value {2}"}, diff --git a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/localization/i18n/LoggingLocalizationResource.java b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/localization/i18n/LoggingLocalizationResource.java index 8fc2cfd3abe..1de9ac1d8b4 100644 --- a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/localization/i18n/LoggingLocalizationResource.java +++ b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/localization/i18n/LoggingLocalizationResource.java @@ -476,9 +476,7 @@ public class LoggingLocalizationResource extends ListResourceBundle { { "dbws_no_wsdl_inline_schema", "The [{0}] WSDL inline schema could not be read."}, // JPA 3.2 { "unknown_cacheRetrieveMode_type", "Unknown {0} type of jakarta.persistence.cache.retrieveMode property"}, - { "unknown_legacy_cacheRetrieveMode_type", "Unknown {0} type of jakarta.persistence.cacheRetrieveMode property"}, { "unknown_cacheStoreMode_type", "Unknown {0} type of jakarta.persistence.cache.storeMode property"}, - { "unknown_legacy_cacheStoreMode_type", "Unknown {0} type of jakarta.persistence.cacheStoreMode property"}, { "unknown_queryTimeoutUnit_type", "Unknown {0} type of eclipselink.query.timeout.unit property"}, { "unknown_queryTimeout_type", "Unknown {0} type of jakarta.persistence.query.timeout property"}, { "error_queryTimeoutParse", "Could not parse jakarta.persistence.query.timeout property value {0}: {1}"}, diff --git a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/EntityManagerFactoryProvider.java b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/EntityManagerFactoryProvider.java index 517c6e261ff..23ab03bcba4 100644 --- a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/EntityManagerFactoryProvider.java +++ b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/EntityManagerFactoryProvider.java @@ -38,6 +38,7 @@ import java.util.Map; import org.eclipse.persistence.config.PersistenceUnitProperties; +import org.eclipse.persistence.config.QueryHints; import org.eclipse.persistence.config.TargetDatabase; import org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.TableCreationType; import org.eclipse.persistence.internal.security.PrivilegedAccessHelper; @@ -85,7 +86,9 @@ public class EntityManagerFactoryProvider { {PersistenceUnitProperties.JDBC_PASSWORD , "eclipselink.jdbc.password"}, {PersistenceUnitProperties.WEAVING , "persistence.tools.weaving"}, {PersistenceUnitProperties.LOGGING_LEVEL + "." + SessionLog.METAMODEL, PersistenceUnitProperties.LOGGING_LEVEL + ".jpa_" + SessionLog.METAMODEL}, - {PersistenceUnitProperties.LOGGING_LEVEL + "." + SessionLog.METADATA, PersistenceUnitProperties.LOGGING_LEVEL + ".ejb_or_" + SessionLog.METADATA} + {PersistenceUnitProperties.LOGGING_LEVEL + "." + SessionLog.METADATA, PersistenceUnitProperties.LOGGING_LEVEL + ".ejb_or_" + SessionLog.METADATA}, + {QueryHints.CACHE_RETRIEVE_MODE, "jakarta.persistence.cacheRetrieveMode"}, + {QueryHints.CACHE_STORE_MODE, "jakarta.persistence.cacheStoreMode"} }; /** @@ -132,8 +135,16 @@ protected static void generateDefaultTables(SchemaManager mgr, TableCreationType * {@link System} property or {@code null} if property identified by {@code propertyKey} does not exist. */ public static String getConfigPropertyAsString(final String propertyKey, final Map overrides) { - final String value = overrides != null ? (String)overrides.get(propertyKey) : null; - return value != null ? value : PrivilegedAccessHelper.getSystemProperty(propertyKey); + Object value = overrides != null ? overrides.get(propertyKey) : null; + if (value != null) { + if (value instanceof String strValue) { + return strValue; + } else { + return value.toString(); + } + } else { + return PrivilegedAccessHelper.getSystemProperty(propertyKey); + } } /** diff --git a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/EntityManagerImpl.java b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/EntityManagerImpl.java index 62b390eb0ad..c20f1c3668e 100644 --- a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/EntityManagerImpl.java +++ b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/EntityManagerImpl.java @@ -935,6 +935,9 @@ protected Object findInternal(ClassDescriptor descriptor, AbstractSession sessio } } + // Translate deprecated properties to the current names + EntityManagerFactoryProvider.translateOldProperties(properties, this.databaseSession); + // Get the read object query and apply the properties to it. // PERF: use descriptor defined query to avoid extra query creation. ReadObjectQuery query = descriptor.getQueryManager().getReadObjectQuery(); @@ -956,8 +959,10 @@ protected Object findInternal(ClassDescriptor descriptor, AbstractSession sessio // Apply any EclipseLink defaults if they haven't been set through // the properties. - if (properties == null || ( !properties.containsKey(QueryHints.CACHE_USAGE) && !properties.containsKey(QueryHints.CACHE_RETRIEVE_MODE) && !properties.containsKey(QueryHints.CACHE_STORE_MODE) - && !properties.containsKey("jakarta.persistence.cacheRetrieveMode") && !properties.containsKey("jakarta.persistence.cacheStoreMode"))) { + if (properties == null || + ( !properties.containsKey(QueryHints.CACHE_USAGE) + && !properties.containsKey(QueryHints.CACHE_RETRIEVE_MODE) + && !properties.containsKey(QueryHints.CACHE_STORE_MODE))) { query.conformResultsInUnitOfWork(); } diff --git a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/FindOptionUtils.java b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/FindOptionUtils.java index ed95f6013cd..ffd9ddab344 100644 --- a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/FindOptionUtils.java +++ b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/FindOptionUtils.java @@ -150,11 +150,9 @@ static Options parse(Map properties, FindOption... options) { return OptionsBuilder.build(properties, options); } - private static final String LEGACY_CACHE_RETRIEVE_MODE = "jakarta.persistence.cacheRetrieveMode"; - // Based on EntityManagerImpl#getQueryHints(Object,OperationType) static CacheRetrieveMode getCacheRetrieveMode(Map properties) { - // Try QueryHints property 1st + // QueryHints property Object propertyValue = properties.get(QueryHints.CACHE_RETRIEVE_MODE); if (propertyValue instanceof CacheRetrieveMode) { return (CacheRetrieveMode) propertyValue; @@ -164,33 +162,17 @@ static CacheRetrieveMode getCacheRetrieveMode(Map properties) { "unknown_cacheRetrieveMode_type", propertyValue.getClass().getName()); } - // Try legacy property as fallback option - propertyValue = properties.get(LEGACY_CACHE_RETRIEVE_MODE); - if (propertyValue instanceof CacheRetrieveMode) { - return (CacheRetrieveMode) propertyValue; - } else if (propertyValue != null) { - AbstractSessionLog.getLog().log(SessionLog.WARNING, - SessionLog.QUERY, - "unknown_legacy_cacheRetrieveMode_type", - propertyValue.getClass().getName()); - } // Default value according to JPA spec. return CacheRetrieveMode.USE; } @SuppressWarnings("unchecked") static void setCacheRetrieveMode(Map properties, CacheRetrieveMode cacheRetrieveMode) { - // Remove legacy property if exists, will be overwritten - properties.remove(LEGACY_CACHE_RETRIEVE_MODE); - // Store new cache retrieve mode as QueryHints.CACHE_RETRIEVE_MODE. - // Previous value, if exists, is overwritten ((Map)properties).put(QueryHints.CACHE_RETRIEVE_MODE, cacheRetrieveMode); } - private static final String LEGACY_CACHE_STORE_MODE = "jakarta.persistence.cacheStoreMode"; - static CacheStoreMode getCacheStoreMode(Map properties) { - // Try QueryHints property 1st + // QueryHints property Object propertyValue = properties.get(QueryHints.CACHE_STORE_MODE); if (propertyValue instanceof CacheStoreMode) { return (CacheStoreMode) propertyValue; @@ -200,26 +182,12 @@ static CacheStoreMode getCacheStoreMode(Map properties) { "unknown_cacheStoreMode_type", propertyValue.getClass().getName()); } - // Try legacy property as fallback option - propertyValue = properties.get(LEGACY_CACHE_STORE_MODE); - if (propertyValue instanceof CacheStoreMode) { - return (CacheStoreMode) propertyValue; - } else if (propertyValue != null) { - AbstractSessionLog.getLog().log(SessionLog.WARNING, - SessionLog.QUERY, - "unknown_legacy_cacheStoreMode_type", - propertyValue.getClass().getName()); - } // Default value according to JPA spec. return CacheStoreMode.USE; } @SuppressWarnings("unchecked") static void setCacheStoreMode(Map properties, CacheStoreMode cacheStoreMode) { - // Remove legacy property if exists, will be overwritten - properties.remove(LEGACY_CACHE_STORE_MODE); - // Store new cache retrieve mode as QueryHints.CACHE_STORE_MODE. - // Previous value, if exists, is overwritten ((Map)properties).put(QueryHints.CACHE_STORE_MODE, cacheStoreMode); } diff --git a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CriteriaBuilderImpl.java b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CriteriaBuilderImpl.java index 2cc0ca86316..db254a238c2 100644 --- a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CriteriaBuilderImpl.java +++ b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CriteriaBuilderImpl.java @@ -889,7 +889,7 @@ public > Predicate between(Expression> buildList(Expression... expressions) { + protected static List> buildList(Expression... expressions) { // Immutable List causes test failures. // Those lists are usually small (size 1-2) and modifications are rare. Default list size is too much. List> list = new ArrayList<>(expressions.length + 2); diff --git a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/FromImpl.java b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/FromImpl.java index 3bcf5ed8c38..08a28e15233 100644 --- a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/FromImpl.java +++ b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/FromImpl.java @@ -19,6 +19,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -33,6 +34,7 @@ import jakarta.persistence.criteria.ListJoin; import jakarta.persistence.criteria.MapJoin; import jakarta.persistence.criteria.Path; +import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.SetJoin; import jakarta.persistence.metamodel.Attribute; import jakarta.persistence.metamodel.Attribute.PersistentAttributeType; @@ -47,10 +49,8 @@ import jakarta.persistence.metamodel.PluralAttribute.CollectionType; import jakarta.persistence.metamodel.SingularAttribute; import jakarta.persistence.metamodel.Type.PersistenceType; - import org.eclipse.persistence.internal.expressions.ObjectExpression; import org.eclipse.persistence.internal.helper.ClassConstants; -import org.eclipse.persistence.internal.jpa.metamodel.ManagedTypeImpl; import org.eclipse.persistence.internal.localization.ExceptionLocalization; /** @@ -526,62 +526,65 @@ public Join join(String attributeName, JoinType jt) { } } - // TODO-API-3.2 @Override public Join join(Class entityClass) { return join(entityClass, JoinType.INNER); } - // TODO-API-3.2 + // Adds join for specified class. + // Initializes ON condition with all mapping attributes to be equal to entity @Id if such @Id exists @Override + @SuppressWarnings("unchecked") public Join join(Class entityClass, JoinType joinType) { - SingularAttribute key = null; - // Search target class attributes for SingularAttribute matching source class - for (Attribute attribute : ((ManagedType)managedType).getAttributes()) { - if (attribute instanceof SingularAttribute - && ((SingularAttribute)attribute).getBindableJavaType().isAssignableFrom(entityClass)) { - if (key == null) { - key = (SingularAttribute)attribute; - // Multiple matching attributes found, can't select the proper one - } else { - throw new IllegalStateException( - ExceptionLocalization.buildMessage("multiple_keys_in_entity", - new String[] { - entityClass.getName(), - this.managedType.getJavaType().getName()})); + // Search target class (this) for SingularAttributes matching source class (entityClass) + JoinImpl join = null; + List equalPredicates = new LinkedList<>(); + for (Attribute attribute : ((ManagedType) managedType).getAttributes()) { + if ((attribute instanceof SingularAttribute) + && ((SingularAttribute) attribute).getBindableJavaType().isAssignableFrom(entityClass)) { + SingularAttribute singularAttribute = (SingularAttribute) attribute; + // Create Join instance if not exists + if (join == null) { + ObjectExpression exp = + ((ObjectExpression) this.currentNode).newDerivedExpressionNamed(singularAttribute.getName()); + switch (joinType) { + case LEFT: + exp.doUseOuterJoin(); + break; + case RIGHT: + throw new UnsupportedOperationException(ExceptionLocalization.buildMessage("RIGHT_JOIN_NOT_SUPPORTED")); + case INNER: + exp.doNotUseOuterJoin(); + } + join = new JoinImpl<>(this, managedType, this.metamodel, entityClass, exp, singularAttribute, joinType); + this.joins.add(join); + join.isJoin = true; } + // Add current target class (this) SingularAttribute into equal predicates if source class has @Id + Expression keyExpr = get(singularAttribute); + equalPredicates.add(new CompoundExpressionImpl(metamodel, + ExpressionImpl.currentNode(keyExpr) + .notEqual(ExpressionImpl.currentNode(join)), + CriteriaBuilderImpl.buildList(keyExpr, join))); } } - if (key == null) { + if (join == null) { throw new IllegalStateException( ExceptionLocalization.buildMessage("no_key_in_entity", new String[] { entityClass.getName(), this.managedType.getJavaType().getName()})); + } else { + // TODO: Need to write test for predicates generated by this method + return join.on(equalPredicates.toArray(new Predicate[equalPredicates.size()])); } - ObjectExpression exp = ((ObjectExpression)this.currentNode).newDerivedExpressionNamed(key.getName()); - switch(joinType) { - case LEFT: - exp.doUseOuterJoin(); - break; - case RIGHT: - throw new UnsupportedOperationException(ExceptionLocalization.buildMessage("RIGHT_JOIN_NOT_SUPPORTED")); - case INNER: - exp.doNotUseOuterJoin(); - } - JoinImpl join = new JoinImpl<>(this, managedType, this.metamodel, entityClass, exp, key, joinType); - this.joins.add(join); - join.isJoin = true; - return join; } - // TODO-API-3.2 @Override public Join join(EntityType entity) { return join(entity, JoinType.INNER); } - // TODO-API-3.2 @Override public Join join(EntityType entity, JoinType joinType) { return join(entity.getJavaType(), joinType);