// Example process to set and restore the default currency.
try {
SystemCurrencyContextHolder.setProcessCurrency(currencyUnit);
} finally {
SystemCurrencyContextHolder.clearProcessCurrency();
}
Broadleaf makes significant use of Monetary concepts that involve scale, rounding, serialization, and deserialization. As a result, Broadleaf makes use of the javax.money.MonetaryAmount
interface to assist with these details, which can be inconsistent and complicated when using raw Number
instances such as float
, double
, or BigDecimal
.
Important components to review include:
javax.money.MonetaryAmount
A high-level interface that defines Money, including Currency and Amount
javax.money.CurrencyUnit
A high-level interface that defines Currency
javax.money.CurrencySupplier
A functional interface that returns a javax.money.CurrencyUnit
com.broadleafcommerce.money.CurrencyConsumer
A functional interface that provides a setter for javax.money.CurrencyUnit
.
Specifically, components that require Currency to construct a MonetaryAmount
com.broadleafcommerce.money.util.MonetaryUtils
A collection of utility methods for creating, transforming, and rounding money
com.broadleafcommerce.data.tracking.core.mapping.money.CurrentCurrencyUtils
A utility to allow for the resolution of preferred currency for a given object
com.broadleafcommerce.money.jackson.BroadleafMoneyModule
A Jackson extension module that provides components for serializing or deserializing Money
The default system currency is defined by the default Locale of the host operating system. If no default Locale is specified, USD
is used as the default system currency.
Additionally, Broadleaf’s Catalogs and Applications each have a default currency. In certain flows that involve currency (e.g. Catalog and Cart), a component can be invoked to set the default currency for the request. These components implement com.broadleafcommerce.data.tracking.core.context.ContextInfoCustomizer
. For example:
com.broadleafcommerce.catalog.service.context.CatalogCurrencyContextInfoCustomizer
com.broadleafcommerce.cart.service.context.CartDefaultCurrencyContextInfoCustomizer
The job of these components is to set the default currency on the ContextInfo
for the current request. These components attempt to resolve the currency based on the current Catalog or Application, depending on the flow. If no currency can be found, then the default system currency is used.
These components can can be overridden to change their behavior, if needed.
It is sometimes useful to override the default currency in a specific request scoped process flow. The following code illustrates how to achieve this.
// Example process to set and restore the default currency.
try {
SystemCurrencyContextHolder.setProcessCurrency(currencyUnit);
} finally {
SystemCurrencyContextHolder.clearProcessCurrency();
}
ContextInfo#getDefaultCurrency()
can be used to determine the default currency for the request. If that value is null, MonetaryUtils#defaultCurrency()
can be used to determine the default system currency.
Additionally, certain objects such as Cart and Product have a currency field on them. If the currency field is populated, then that currency is used for operations that involve that object and its children.
Use com.broadleafcommerce.data.tracking.core.mapping.money.CurrentCurrencyUtils
to resolve the current currency in any situation. The resolveCurrency
method takes in an object and a ContextInfo
. If the object is not null and is a CurrencySupplier
and its currency is not null, then it’s used. Otherwise, if the ContextInfo
is not null and its default currency is not null, then it’s used instead. Finally, if no other currency could be determined then the system currency is used.
With RDBMS (JPA / Hibernate), data is stored in relational database tables. Some of the columns hold JSON data that is serialized and deserialized by Hibernate.
High-level objects such as Cart
and Product
contain a persistent currency field. If their children are JPA entities and have monetary concerns (i.e. CartItem
) then they contain a Transient
field for currency and amount fields are represented as BigDecimal
. These objects have mutators (getter/setters) for MonetaryAmount
that translates to/from BigDecimal
using the currency on the object. The transient currency is set prior to mapping between the business (projection) domain and the persistent domain. This happens in a preFromMe
and preToMe
method, where the currency is determined and set on the child objects.
For JSON representations that are stored in RDBMS fields (e.g. FulfillmentGroup
), they are stored as JSON MonetaryAmount
fields, which means that they contain a serialized amount and currency.
Broadleaf does not currently make use of Solr’s Currency functionality due to the fact that it requires a managed list of currencies and exchange rates. Rather, Broadleaf stores Money in 2 Solr fields defined by the following dynamic fields:
*_money
(Double)
Contains the amount
*_currency
(String)
Contains the currency code
This allows us to uniquely identify each of these necessary pieces of data on a Solr document and construct a MonetaryAmount
instance based on the values.