Self-Managed Commerce 8.8.x Upgrade Notes
Upgrade notes
The upgrading Elastic Path guide provides general instructions on upgrading Elastic Path projects. This page provides details about specific changes that may be required to your customizations when upgrading to Self-Managed Commerce 8.8.
Core changes
Remove Java Security Manager usage
All usage of the deprecated System.getSecurityManager() API has been removed from the Cortex API platform. This API was deprecated for removal in
Java 17 and its continued use would result in build or runtime warnings, and eventual failures in future Java versions where the API is fully removed.
Customers who have customizations that reference the System.getSecurityManager() API should refactor away from use of this API.
Upgraded SLF4j from 1.7.x to 2.0.x and Logback from 1.2.x to 1.5.x
SLF4j was upgraded from 1.7.x to 2.0.x and Logback from 1.2.x to 1.5.x. As part of this change, Log4j was also upgraded from 2.17.x to 2.24.x, and the
Log4j-to-SLF4j bridge artifact was renamed from log4j-slf4j-impl to log4j-slf4j2-impl to align with the SLF4j 2.x API. The legacy
log4j-over-slf4j and slf4j-log4j12 bridge artifacts have been removed as they are no longer needed.
Customers who have customizations that declare direct dependencies on any of these logging libraries should update their Maven POMs to reference the
new versions and artifact names. Specifically, any references to log4j-slf4j-impl should be changed to log4j-slf4j2-impl. Custom OSGi bundles that
import org.slf4j packages should also be updated to reference the 2.0.x version range. Additionally, note that Logback 1.3+ removes native JMX
support; a custom JMX endpoint for logging has been introduced to maintain Query Analyzer functionality.
In the new Logback version, Janino (the Java compiler library for evaluating condition=isDefined(...) expressions) became an optional dependency —
not bundled by default. Without Janino on the classpath, Logback silently skips <if condition='...'> blocks entirely. Therefore, customers with
customized logback.xml configurations that use Logback if/then/else conditional blocks should migrate those configurations to use the property
default syntax (e.g., ${propertyName:-defaultValue}) to ensure compatibility with Logback 1.5 and continued log output in deployed environments.
Replace deprecated ServiceMix dependencies with Elastic Path-maintained wrapped bundles
Customers or partners who reference org.apache.servicemix.bundles artifacts directly in their Maven POMs or OSGi feature configurations must update
those references to the corresponding com.elasticpath.wrappedbundles artifacts. Below is a list of the required transformations:
org.apache.servicemix.bundles:org.apache.servicemix.bundles.aspectj→com.elasticpath.wrappedbundles:wrapped-aspectjorg.apache.servicemix.bundles:org.apache.servicemix.bundles.commons-collections→com.elasticpath.wrappedbundles:wrapped-commons-collectionsorg.apache.servicemix.bundles:org.apache.servicemix.bundles.ehcache→com.elasticpath.wrappedbundles:wrapped-ehcacheorg.apache.servicemix.bundles:org.apache.servicemix.bundles.spring-aop→com.elasticpath.wrappedbundles:wrapped-spring-aoporg.apache.servicemix.bundles:org.apache.servicemix.bundles.spring-beans→com.elasticpath.wrappedbundles:wrapped-spring-beansorg.apache.servicemix.bundles:org.apache.servicemix.bundles.spring-context→com.elasticpath.wrappedbundles:wrapped-spring-contextorg.apache.servicemix.bundles:org.apache.servicemix.bundles.spring-core→com.elasticpath.wrappedbundles:wrapped-spring-coreorg.apache.servicemix.bundles:org.apache.servicemix.bundles.spring-data-commons→com.elasticpath.wrappedbundles:wrapped-spring-data-commonsorg.apache.servicemix.bundles:org.apache.servicemix.bundles.spring-expression→com.elasticpath.wrappedbundles:wrapped-spring-expressionorg.apache.servicemix.bundles:org.apache.servicemix.bundles.spring-jdbc→com.elasticpath.wrappedbundles:wrapped-spring-jdbcorg.apache.servicemix.bundles:org.apache.servicemix.bundles.spring-jms→com.elasticpath.wrappedbundles:wrapped-spring-jmsorg.apache.servicemix.bundles:org.apache.servicemix.bundles.spring-orm→com.elasticpath.wrappedbundles:wrapped-spring-ormorg.apache.servicemix.bundles:org.apache.servicemix.bundles.spring-security-config→com.elasticpath.wrappedbundles:wrapped-spring-security-configorg.apache.servicemix.bundles:org.apache.servicemix.bundles.spring-security-core→com.elasticpath.wrappedbundles:wrapped-spring-security-coreorg.apache.servicemix.bundles:org.apache.servicemix.bundles.spring-security-data→com.elasticpath.wrappedbundles:wrapped-spring-security-dataorg.apache.servicemix.bundles:org.apache.servicemix.bundles.spring-tx→com.elasticpath.wrappedbundles:wrapped-spring-txorg.apache.servicemix.bundles:org.apache.servicemix.bundles.spring-web→com.elasticpath.wrappedbundles:wrapped-spring-web
The org.apache.servicemix.bundles:org.apache.servicemix.bundles.spring-context-support bundle is no longer needed and any references to this bundle can be removed.
Improved promotion category exclusion handling for products in overlapping category hierarchies
When configuring a promotion condition such as "at least 1 item from category A, excluding items from subcategory B," products assigned to both the parent category A and the excluded subcategory B are now correctly treated as eligible for the promotion. Previously, such products were incorrectly excluded, preventing the promotion from applying even though the product was directly assigned to the intended included category. Products that belong to an excluded category that is not part of the included category hierarchy remain ineligible as expected.
This change affects promotion condition evaluation as well as CartCategoryAmountDiscountImpl and CartCategoryPercentDiscountImpl promotion
actions, which now use the corrected exclusion logic via PromotionRuleDelegate#isProductInNotExcludedCategory. Merchants who have customized
CartCategoryAmountDiscountImpl, CartCategoryPercentDiscountImpl, PromotionRuleDelegateImpl, or PromotionRuleExceptionsServiceImpl should
review their customizations for compatibility with these changes. Additionally, the isInCategory method has been removed from the ProductLookup
interface and its associated cache (isInCategoryCache) has been removed; any custom code referencing these should be updated accordingly.
Build now fails on duplicate POM dependency declarations
The Maven build process has been enhanced to detect and fail on duplicate dependency version declarations within project POM files. Previously, Maven
would only emit warnings when duplicate dependencies were found, which could silently threaten build stability and lead to unpredictable behavior.
These warnings are now treated as errors, enforcing cleaner and more reliable dependency management. This is achieved by adding the
banDuplicatePomDependencyVersions rule to the maven-enforcer-plugin configuration in the root POM, within a new execution phase called
enforce-ban-on-duplicate-dependencies.
Customers who have customized their extensions POMs should audit their dependency declarations to ensure no duplicates exist before upgrading, as any pre-existing duplicate dependencies will cause the build to fail.
Job Pause Settings for "peak mode" management
For customers with custom Quartz jobs, the pausable and critical job name lists (nonCriticalPausableJobNames and criticalJobNames) extensible
lists should be reviewed. Custom jobs should be added to either list depending on whether it should be executed during peak transaction events or not.
Jobs not specified in either list will not be paused when the job pause settings are activated.
Simplified EhCache Spring XML Configuration via custom ep-caches:cache namespace
A new custom Spring XML namespace (ep-caches:cache) has been introduced to streamline the declaration of EhCache-backed caches.
You can optionally replace manually defined caches like this:
<bean id="taxCodeByCodeEhCache" class="com.elasticpath.commons.beanframework.EhCacheDefaultConfigurationFactoryBean">
<property name="name" value="taxCodeByCodeCache"/>
<property name="cacheManager" ref="epEhcacheManager"/>
<property name="timeToLive" value="3600"/>
<property name="timeToIdle" value="3600"/>
<property name="maxEntriesLocalHeap" value="10000"/>
</bean>
<bean id="taxCodeByCodeCache" factory-bean="localCacheFactory" factory-method="createCache" depends-on="taxCodeByCodeEhCache">
<constructor-arg value="taxCodeByCodeCache"/>
</bean>
With the simplified namespace like this:
<ep-caches:cache id="taxCodeByCodeCache" timeToLive="3600" timeToIdle="3600" maxEntries="10000"/>
For more information, see Cortex and Integration Server Application Caches.
As part of this change, the EhCacheDefaultConfigurationFactoryBean class has been relocated from com.elasticpath.commons.beanframework to
com.elasticpath.cache.spring. Any custom Spring XML files or Java code that reference the old fully-qualified class name must be updated to use the
new package.
Custom promotion conditions and actions now use extensible Spring autowiring
Previously, adding custom promotion conditions or actions required overriding the entire ruleServiceLocal Spring bean definition to inject the
allConditions and allActions lists. This was an invasive customization that risked breaking other functionality and made upgrades more difficult.
The allConditions and allActions lists in RuleServiceImpl are now autowired Spring lists. Custom promotion conditions and actions can
be added simply by declaring a Spring bean of the appropriate type (RuleCondition or RuleAction), which will be automatically discovered and
included without any need to redefine the core service bean.
Customers who previously overrode ruleServiceLocal solely to inject custom conditions or actions into these lists should remove
that override and instead register their custom beans directly. Any explicit allConditions or allActions list definitions in extension Spring XML
configuration (e.g., ext-service.xml) should also be removed, as the platform's built-in elements are no longer defined this way either.
Removed deprecated shopping cart deletion methods
Two deprecated methods for directly deleting shopping carts — ShoppingCartService#deleteShoppingCartsByGuid and
ShoppingCartService#deleteAllShoppingCartsByShopperUid — have been removed from the ShoppingCartService interface and its implementation. Shopping
cart deletion is now exclusively managed by the PurgeCartsBatchProcessor, ensuring consistent and performant cart lifecycle management.
The associated named queries DELETE_SHOPPING_CART_BY_GUIDS, DELETE_SHOPPING_CARTS_BY_SHOPPER_UID, and
DISABLE_PARENT_CHILD_CART_ITEM_RELATION_BY_SHOPPER_UID have also been removed. Any custom code invoking these methods
must be updated to use the preferred deactivation equivalents: deactivateShoppingCartsByGuid and deactivateAllShoppingCartsByShopperUid.
Removed unused fields and methods from ShoppingCartImpl and ShoppingCart
Several unused fields and methods have been removed from ShoppingCartImpl and the ShoppingCart interface as part of an ongoing effort to reduce
technical debt and simplify the shopping cart API. The removed fields include codeValid, mergedNotification, itemWithNoTierOneFromWishList,
giftCertificateService, and discountCalculator. The removed methods include isCodeValid, setCodeValid, isMergedNotification,
setMergedNotification, hasItemWithNoTierOneFromWishList, setItemWithNoTierOneFromWishList, getSubtotalOfShippableItems,
getCustomerEmailAddress, getCustomerBusinessNumber, and isCustomerAnonymous.
Associated logic that previously set mergedNotification during cart merges and itemWithNoTierOneFromWishList when adding wishlist items has also
been removed from ShoppingCartMergerImpl and CartDirectorServiceImpl, as these flags were not being consumed anywhere in the platform.
Any custom code that references the removed fields or methods on ShoppingCart or ShoppingCartImpl — including subclasses, decorators, or direct
callers — will need to be updated. If your customization relied on the merge notification or wishlist tier-one flag behavior, equivalent logic will
need to be reimplemented independently.
Removed deprecated com.elasticpath.commons.util.Collections class
The long-deprecated com.elasticpath.commons.util.Collections utility class has been removed from ep-core. This class previously provided
emptySortedSet() and emptySortedMap() helper methods as a supplement to java.util.Collections.
Any custom code that references this class must be updated. Replace calls to Collections.emptySortedSet() with Guava's ImmutableSortedSet.of(),
and replace calls to Collections.emptySortedMap() with Guava's ImmutableSortedMap.of().
Removed unused Greenmail test dependency from bill of materials and module POMs
The unused greenmail (com.icegreen, version 1.3) test dependency has been removed from the platform's bill-of-materials and all module POMs where it
was referenced, including ep-email, ep-test-application, and ep-core-fittests. This dependency was not actively used and its removal reduces
unnecessary third-party library references, improving build cleanliness and reducing potential security exposure from unmaintained libraries.
Customizations that rely on greenmail being provided transitively through the bill-of-materials should explicitly declare this
dependency in their own POMs if they still require it for testing purposes.
Removed unused PropertyService
The PropertyService interface and its implementation PropertyServiceImpl have been removed from the commerce engine core, as they were no longer
in use. The associated propertyService Spring bean definition and the ContextIdNames.PROPERTIES_SERVICE constant have also been deleted.
Customizations that reference com.elasticpath.service.misc.PropertyService,
com.elasticpath.service.misc.impl.PropertyServiceImpl, or ContextIdNames.PROPERTIES_SERVICE will need to remove or replace those references. Any
custom Spring configurations that depend on the propertyService bean should also be updated accordingly.
Removed unused fields from AbstractRuleEngineImpl
Several unused fields have been removed from AbstractRuleEngineImpl: promotionRuleDelegate, ruleEngineSessionFactory, ruleEngineRuleStrategy,
couponConfigDao, productSkuConverter, and shoppingCartConverter. Their corresponding getters, setters, and Spring bean injections have also been
removed from the epRuleEngine bean definitions across all relevant Spring configuration files.
This is primarily a code cleanup change with no functional impact on promotion or rule engine behavior. However, merchants or developers who have
customized the epRuleEngine Spring bean definition or extended AbstractRuleEngineImpl should review their configurations and remove any references
to these now-deleted properties to avoid Spring initialization errors.
Replaced org.drools.core.util.StringUtils with org.apache.commons.lang3.StringUtils
All platform usages of org.drools.core.util.StringUtils have been replaced with the standard org.apache.commons.lang3.StringUtils. This
standardizes string utility usage across the codebase.
org.drools.core.util.StringUtils has also been added to the Checkstyle IllegalImport list, meaning any code — including customizations — that
imports this class will now fail the Checkstyle build check. Customers with custom code that imports org.drools.core.util.StringUtils must update
those imports to use org.apache.commons.lang3.StringUtils instead.
To assist with this migration, ast-grep upgrade recipes (PB-14031-drools-stringutils-to-commons-lang3.yml and
PB-14031-drools-stringutils-to-commons-lang3-static.yml) have been provided under upgrade/recipes/8.8.x/ to automatically replace both regular and
static imports in custom Java code when running the Self-Managed Commerce Upgrader Tool.
Improved Extensibility: Private methods and fields changed to protected
A broad set of private methods, fields, and constants across the Elastic Path Commerce platform have been changed to protected visibility (or
public where interface contracts or framework requirements demand it). New protected getters and setters have also been added for previously
inaccessible members. The affected areas span core domain objects, services, search/indexing, checkout, pricing, tax calculation, promotions, coupon
handling, shopping cart logic, and Commerce Manager UI components.
These changes significantly reduce the need for disruptive or fragile customization workarounds (such as reflection or full class replacement) when extending platform behavior. Customers who have already implemented such workarounds may be able to simplify or remove them in favor of standard subclassing or method overriding.
Customers with existing customizations should review their extensions against the changed classes — particularly ShoppingCartImpl,
CheckoutServiceImpl, OrderFactoryImpl, OrderSkuFactoryImpl, TaxCalculationServiceImpl, TaxOperationServiceImpl,
ElasticPathPromotionsCalculator, AbstractEpDialog, and the various Promotions UI editor and search tab classes — to determine whether
simplifications are possible. Note that in some cases methods have been promoted to public visibility (e.g., OrderSkuImpl.getOrderUidPk(),
CouponUsageModelDtoInsertUpdateImporterImpl.importCouponDtos(), and several Commerce Manager dialog and UI component methods), which may affect API
compatibility if these classes were previously subclassed.
Maven Checkstyle Plugin upgraded to 3.6.0 (Checkstyle 9.3)
The Maven Checkstyle plugin has been upgraded from version 2.17 to 3.6.0, which updates the underlying Checkstyle engine from version 6.11.2 to 9.3. This ensures that code quality checks are enforced using a modern, actively maintained version of the tooling, and resolves known issues present in older versions of the plugin.
Customers who have customized or extended Elastic Path's code-checking rules, or who have added their own Checkstyle configurations, should review
their configurations for compatibility with Checkstyle 9.3. Some customized source code fixes may be required to comply with the
updated rules, including whitespace corrections in varargs declarations (e.g., String... instead of String ...) and removal of redundant final
modifiers on abstract method parameters.
Removed OWASP ESAPI dependencies
All OWASP ESAPI dependencies (esapi, esapi-osgi-bundle) have been removed from the Self-Managed Commerce platform (ep-commerce and
api-platform). Although ESAPI was included as a security library, it was not registered as a Servlet filter and was not actively protecting any
Cortex API endpoints. Its presence only served to introduce a number of vulnerable transitive dependencies, including bsh-core,
commons-configuration, commons-fileupload, and commons-lang.
Customizations that have a direct dependency on ESAPI libraries will need to be managed independently, as they are no longer provided by the platform.
New ShoppingItemDtoBuilder for simplified shopping item DTO construction
A new ShoppingItemDtoBuilder interface and ShoppingItemDtoBuilderImpl implementation have been introduced to provide a cleaner, more extensible
way to construct ShoppingItemDto objects. Previously, ShoppingItemDtoFactory exposed several overloaded methods that were difficult to extend and
caused confusion. The new builder pattern replaces this with a fluent API supporting SKU code, quantity, item configuration, fields, parent GUID,
shopping cart memento, and selection state.
The existing ShoppingItemDtoFactoryImpl has been refactored to use the new builder internally, so existing behavior is preserved. The builder can
also be accessed directly via the static ShoppingItemDto.builder(bundleIdentifier, productSkuLookup) factory method.
Teams that have customized ShoppingItemDto or ShoppingItemDtoFactoryImpl should review their implementations. The
ShoppingItemDtoBuilderImpl provides two extension points — createNewDto() for instantiating a custom DTO subclass, and getNewBuilder() for
returning a custom builder instance — which should be overridden if a custom ShoppingItemDto subclass is in use.
Removed eagerly fetched customer role relationship
Previously, every customer loaded from the database triggered a cascade of eager JPA fetches: from CustomerImpl to its set of CustomerGroupImpl
objects, and then from each CustomerGroupImpl to its set of CustomerRoleImpl objects stored in the TCUSTOMERGROUPROLEX table. This resulted in a
significant number of unnecessary database queries, as the only value ever stored in that table was the static string ROLE_CUSTOMER. The
ROLE_CUSTOMER Spring Security authority is now hardcoded as a constant in CustomerImpl.getAuthorities(), eliminating the need for the database
relationship entirely.
The TCUSTOMERGROUPROLEX table has been removed. The CustomerRole interface and CustomerRoleImpl class, along with the
CustomerGroupService.removeAllRoles() method, have been deprecated and removed from active use. The customer_roles element in customer group
import/export XML files is retained for backward compatibility but is now ignored during import and export operations. The CUSTOMER_ROLES dependent
element type has been removed from the DependentElementType enum, and the CustomerGroupCollectionsStrategy class has been deleted.
Customizations that reference CustomerRoleImpl, CustomerGroupService.removeAllRoles(), the ContextIdNames.CUSTOMER_ROLE bean, or the
customer_roles XML element in customer group data files should be reviewed as these are no longer functional. Any custom logic that depended on
configurable per-group Spring Security authorities via TCUSTOMERGROUPROLEX will need to be reimplemented using an alternative approach.
Shopping cart item lookup optimized to avoid expensive recursive flattening
ShoppingCartImpl has been updated to retrieve cart items directly from the flat list stored in the cart memento, replacing a recursive
tree-flattening operation that was unnecessarily invoked when looking up items by identifier. This improves the performance of several shopping cart
operations, including item lookup, item removal, shipment type evaluation, and discount clearing.
The signature of the protected method getAllShoppingItemsStream() has changed: it now accepts a boolean parameter (includingRemoved) that controls
whether soft-deleted cart items are included in the stream. Any custom subclasses of ShoppingCartImpl that override this method will need to be
updated to match the new signature.
Extension point framework output converter classes moved to a new package
Several extension point framework converter classes that convert extension point entities back into domain objects have been relocated from the
com.elasticpath.xpf.converters package to a new com.elasticpath.xpf.converters.output package. The affected classes are:
StructuredErrorMessageConverter, StructuredErrorMessageTypeConverter, StructuredErrorResolutionConverter, OrderHoldConverter,
InventoryDtoConverter, XPFInventoryExecutionResultConverter, PromotionActionToDiscountConverter, TaxJournalConverter, and
TaxJournalConverterImpl.
If your customizations reference any of these classes directly — either through Java imports or Spring XML bean definitions — you must update those
references to use the new com.elasticpath.xpf.converters.output package. Upgrade recipes using ast-grep are provided in
upgrade/recipes/8.8.x/PB-13069-xpf-output-converters-package.yml to assist with automating these import changes across both Java and XML files.
Cortex changes
Product SKU availability error messages now use ISO 8601 date format
When a shopper attempts to add an item to their cart that is not yet available or is no longer available for purchase, the structured error message
returned by the platform previously included dates formatted in a localized US short date format (e.g., 9/4/26 12:00 AM). These dates are now
formatted using the ISO 8601 standard (e.g., 2026-09-04T00:00:00), providing a consistent, locale-independent representation.
This change affects the available-date field in item.not.yet.available errors and the expiry-date field in item.no.longer.available errors.
Any integrations, customizations, or client applications that parse these date values from structured error message responses should be reviewed and
updated to handle the new ISO 8601 format.
Commerce Manager changes
Commerce Manager module customizations
If your project includes copies of Commerce Manager modules under extensions/cm/ext-cm-modules - a common pattern used to gain access to ext-core
classes - you will need to migrate these customizations before upgrading to Self-Managed Commerce 8.7. The upgraded version of Tycho included in
Self-Managed Commerce 8.7 no longer permits multiple modules sharing the same artifact ID, and will fail at compile time with a "Duplicate reactor
project IUs" error if these copied modules are present.
To resolve this, Self-Managed Commerce 8.8 now allows the standard commerce-manager/cm-modules/cm-plugins modules to access ext-core classes
directly, eliminating the need for the copied modules entirely. You will need to migrate any customizations from your extensions/cm/ext-cm-modules
modules into their corresponding commerce-manager/cm-modules/cm-plugins modules, then delete the copied modules. If you have accumulated significant
customizations across many modules, this migration can be time-consuming to do manually. Therefore we recommend using an AI coding tool such as Claude
Code to automate the process. You can use a prompt like the following:
This repo represents a customized version of Self-Managed Commerce. We are in the process of upgrading to version 8.7. In previous versions, Commerce Manager modules (in commerce-manager/cm-modules/cm-plugins) could not access ext-core classes. To work around this, some modules were copied into the extensions/cm/ext-cm-modules folder so they could access custom services in ext-core. However, the new version of Tycho in Self-Managed Commerce 8.7 no longer allows multiple modules with the same artifact ID — it causes a "Duplicate reactor project IUs" error during compilation. Self-Managed Commerce 8.7 now allows the platform modules to access ext-core classes directly. Please migrate the customizations in the extensions/cm/ext-cm-modules modules back into the corresponding commerce-manager/cm-modules/cm-plugins modules and delete the extensions/cm/ext-cm-modules modules. If there is no corresponding commerce-manager/cm-modules/cm-plugins module, leave it in extensions/cm/ext-cm-modules.
BaseConditionalExpressionAction replaced by AbstractConditionalExpressionAction
The BaseConditionalExpressionAction class in Commerce Manager has been renamed to AbstractConditionalExpressionAction and converted to an abstract
class. The placeholder getTargetIdentifier() method, which previously returned a hardcoded stub value ("!replace me on valid value!"), has been
removed, enforcing that all subclasses provide their own valid implementation.
The built-in action classes — CreateConditionalExpressionAction, DeleteConditionalExpressionAction, and EditConditionalExpressionAction — have
been updated to reflect this change. Customers with customizations that extend BaseConditionalExpressionAction must update their code to extend
AbstractConditionalExpressionAction instead, and ensure a proper getTargetIdentifier() implementation is provided.
Replacement for Locale.getAvailableLocales()
A newly created master catalog with all available languages selected could not be opened in Commerce Manager. Attempting to open the catalog resulted
in an IllegalArgumentException and a persistence error, making the catalog inaccessible.
The root cause was that certain locales provided by the JVM (e.g., sr__#Latn) cannot be serialized to a string and then deserialized back to a
Locale object using the Apache Commons LocaleUtils.toLocale() method, which is used internally for catalog locale persistence. A new
LocaleUtils.getAvailableLocales() method has been added to com.elasticpath.commons.util.impl.LocaleUtils that filters out these incompatible
locales and returns only those that can be safely round-tripped.
Customizations that call Locale.getAvailableLocales() directly - particularly in contexts where locales are persisted or compared against
catalog-supported locales—should consider migrating to the new LocaleUtils.getAvailableLocales() method to avoid similar issues. Additionally, the
return type of Catalog.getSupportedLocales() has been changed from Collection<Locale> to SortedSet<Locale>; any custom code referencing this
method signature may require a minor update.
Batch Server changes
Configurable Quartz batch job schedules via ep.properties
Batch server Quartz job cron schedules can now be overridden in ep.properties without requiring modifications to quartz.xml. This gives operators
greater flexibility to tune job timing to suit their operational needs, such as shifting resource-intensive cleanup jobs to off-peak hours.
The following ep.batch.job.<jobName>.cronExpression properties are now supported: releaseShipment, cleanupOrderLocks,
cleanupExpiredOAuth2Tokens, cleanupAbandonedCarts, abandonedCartEvents, cleanupInactiveCarts, cleanupAnonymousCustomers,
cleanupFailedOrders, cleanupOrphanedOrderPaymentInstruments, cleanupOrphanedOrderPaymentGuids, cleanupOrphanedPaymentInstruments,
cleanupChangesets, expiredDataPointValuesJobProcessor, dataPointRevokedConsentsJobProcessor, relayOutboxMessages, cleanupCompletedOrders,
and encryptCustomerPasswords. All existing default schedules are preserved when no override is set.
For more information, see Batch Server Properties.
Promotion recompilation and catalog promotion index updates now use database backed job tracking
Previously, the Search Server used two filesystem-based properties files (ruleUpdate.properties and catalogPromo.properties) to track the last time
promotion rules were compiled and the last time catalog promotion rules were checked for product index updates. In multi-node or multi-threaded
environments, concurrent writes to these files could cause race conditions resulting in incorrect timestamps, leading to intermittent failures where
some promotions were not recompiled after being edited. Additionally, these files could be erased during a deployment, causing unnecessary full
recompilations or missed updates.
Both files have been replaced with a new TJOBEXECUTION database table, which stores the last execution date for each tracked job. The
DBCompilingRuleEngineImpl and CatalogPromotionMonitor classes now read and write this state via the new JobExecutionService, eliminating
filesystem dependencies and ensuring consistent behavior across all application nodes.
If you have customized DBCompilingRuleEngineImpl or CatalogPromotionMonitor, note that the propertiesDao dependency has been removed from both
classes and replaced with jobExecutionService. Custom Spring bean definitions referencing propertiesDao on these beans should be updated
accordingly.
Import/Export changes
Improved Import/Export error and warning log messages
Customers who have customized Import/Export controllers or who extend ImportAPIServiceImpl should ensure their implementations wire in the messageResolver bean (as introduced in the updated Spring configuration) to benefit from the logging improvement. Additionally, acceptance tests that previously asserted on raw error codes (e.g., IE-30402) have been updated to assert on resolved message text instead, so any similar custom test assertions should be updated accordingly.
Removed unused fields and bean definition from PricingExporterImpl
The productService and productLoadTuner fields, along with their getter/setter methods, have been removed from PricingExporterImpl, as they were
never used in the class's logic. The associated productTunerForPricing Spring bean definition, which was solely referenced by this exporter, has
also been deleted from the import/export service configuration.
This is a code cleanup change with no functional impact on pricing export behavior. However, customers who have subclassed PricingExporterImpl or
injected/referenced the productTunerForPricing bean in custom Spring configurations should remove those references to avoid startup errors or
compilation issues after upgrading.
Deprecated Hamcrest dependencies replaced with consolidated library
The hamcrest-core and hamcrest-library dependencies have been replaced throughout the platform with the single consolidated
org.hamcrest:hamcrest 2.2 dependency. In Hamcrest 2.2, the older split artifacts contain no classes and exist only for backwards compatibility, so
continuing to reference them could result in empty or conflicting dependencies on the classpath. The Hamcrest version used in the bill of materials
has also been updated from 1.3 to 2.2.
The legacy hamcrest-core and hamcrest-library artifacts have been explicitly excluded from transitive dependencies pulled in by third-party
libraries such as JUnit 4, JMock, Awaitility, REST Assured, WireMock, and Tempus Fugit. Additionally, all three legacy artifacts (hamcrest-all,
hamcrest-core, and hamcrest-library) are now banned from the build and will cause a build failure if introduced.
Customers with customizations that declare a direct dependency on org.hamcrest:hamcrest-core or org.hamcrest:hamcrest-library should update those
references to org.hamcrest:hamcrest. The deprecated @Factory annotation from the Hamcrest library has also been removed from custom matcher
classes, and any custom matchers in extensions that use this annotation should be updated accordingly.
Test changes
Selenium test framework: fix intermittent failures from nested retry calls
Several page object methods in the Selenium test framework called the retryFunction() polling wrapper from inside another retryFunction() body.
When the inner retry exhausted its attempts, the failure was wrapped in a timeout exception that the outer retry did not ignore, causing it to
propagate immediately. As a result, composite multi-step interactions received only a single attempt instead of being retried as intended.
A new retryAttempts() method has been added as a safe primitive for inner retry logic. Unlike retryFunction(), it re-throws the original assertion
error directly on exhaustion rather than wrapping it in a timeout exception, making it safe to call from within an outer retryFunction() body. The
existing retryFunction() method now detects and explicitly forbids nested calls by throwing an IllegalStateException, turning a previously silent
bug into a clearly reported error.
Customizations that extend AbstractPageObject or widget classes and make use of retryFunction() should be reviewed to ensure they do not call
retryFunction() from inside another retryFunction() body. Any such nested usage should be updated to use the new retryAttempts() method for the
inner retry logic.
Support for mocking sealed classes in Java 17 bytecode
In Java 17, enum types are effectively sealed classes. This caused failures in unit tests that used Mockito to mock or spy on enum types (such as
AllocationEventType), because Mockito's default mock maker works by creating subclasses, which is not permitted for sealed classes.
To resolve this, the mockito-inline dependency has been added to the bill of materials and to the ep-core module. The mockito-inline library
uses Java instrumentation instead of subclassing, allowing Mockito to mock sealed and final classes without errors. This is a compatibility fix in
preparation for upgrading to Java 17 bytecode, and does not affect runtime behaviour.
If you have custom modules that mock enums or other sealed classes in unit tests and encounter similar Mockito errors, you may need to add the
mockito-inline dependency (scoped to test) to those modules as well.
Strict fatal JavaScript exception checking enabled by default in system tests
System tests now fail immediately when a fatal JavaScript exception is detected, rather than treating it as a retryable error. This is controlled by
the property ep.selenium.ignore.fatal.js.exceptions, whose default value has changed from true (lenient/ignore) to false (strict/fail-fast).
If your customized system tests rely on the previous lenient behavior, you can restore it by explicitly setting
ep.selenium.ignore.fatal.js.exceptions=true in your test configuration. However, it is recommended to update affected tests to be compatible with
strict mode, as lenient behavior may mask real defects caused by ambiguous element selectors or other JavaScript errors.
Fixed intermittent test failures caused by ambiguous widget selectors
Automated tests for Commerce Manager could intermittently fail because the internal findRwtIdForSelector function used a browser query method that
silently returns only the first matching element when multiple elements match a given selector. Depending on the order of test steps, a different
element could be returned each time, producing unpredictable results.
The function has been updated to query for all matching elements and throw a descriptive error if more than one is found, making ambiguous selectors immediately visible rather than causing hard-to-diagnose flaky tests. Several element selectors used in the system tests — including those for the store list, product category table, shipping region dialog, and category wizard attributes — have also been made more specific so they reliably target the intended element without ambiguity.
If you have custom test definitions that define CSS selectors to match specific widgets, you should review your selectors to ensure they uniquely identify the intended element, as selectors matching multiple elements will now cause an explicit test failure.
Database changes
Local Oracle database setup
The reset-db step for local Oracle database setup previously failed with an ORA-12919: Can not drop the default permanent tablespace error. This
occurred because the reset script incorrectly attempted to drop the USERS tablespace, which Oracle designates as the default permanent tablespace
and does not allow to be dropped.
The Oracle reset script (oracle.sproc) has been reworked to instead drop and recreate the Pluggable Database (orclpdb1) from the Oracle Container
Database root, then create dedicated tablespaces (COMMERCE and COMMERCETEMP) and the COMMERCEDB user within the Oracle Pluggable Database. The
oracle-dev-db Maven profile in settings.xml and individual-settings.xml has also been updated with corrected default values to match this new
approach.
Developers who have configured a local Oracle database should update their ~/.m2/settings.xml oracle-dev-db profile to use the new settings:
username COMMERCEDB (replacing C##COMMERCEDB), tablespaces COMMERCE and COMMERCETEMP (replacing USERS and TEMP), and the new
epdb.reset_databasename property set to ORCLCDB. Refer to the updated Oracle setup documentation for
the full configuration.