-
-
Notifications
You must be signed in to change notification settings - Fork 101
Description
Maybe I'm not understanding this, so please correct me if I'm mistaken, but there seems to be a huge overhead in creating monetary amounts in the real world.
Let's say a client is processing connections to a financial server in several threads. Each thread wants to simply create a MonetaryAmount
instance using the default implementation. Naturally that would be Monetary.getDefaultAmountFactory()
, but we don't know what the amount factory will be until runtime (which is why we're not hard-coding the implementation to use any particular amount factory). But there's a problem: javax.money.MonetaryAmountFactory
specifically says it is not guaranteed to be thread-safe:
Implementation specification
Instances of this interface are not required to be thread-safe!
Since we are plugging in a serializer/deserializer to our serialization library (e.g. Jackson), we have no idea if these will be called from a single thread or not, so we are forced to call Monetary.getDefaultAmountFactory()
each time, are we not?
Unfortunately javax.money.Monetary.getDefaultAmountFactory()
has a huge overhead—it actually invokes all the Java SPI lookup infrastructure each time!!
public static MonetaryAmountFactory<?> getDefaultAmountFactory() {
return Optional.ofNullable(monetaryAmountsSingletonSpi())
.orElseThrow(() -> new MonetaryException("No MonetaryAmountsSingletonSpi loaded."))
.getDefaultAmountFactory();
}
private static MonetaryAmountsSingletonSpi monetaryAmountsSingletonSpi() {
try {
return Bootstrap.getService(MonetaryAmountsSingletonSpi.class);
} catch (Exception e) {
Logger.getLogger(Monetary.class.getName())
.log(Level.SEVERE, "Failed to load MonetaryAmountsSingletonSpi.", e);
return null;
}
}
So for each one of those thousands or millions of monetary amounts, the application is supposed to invoke the Java SPI infrastructure to look up the default amount MonetaryAmountFactory
? I haven't ran any tests, but just on the face of it that sounds absurd. I need to keep the default MonetaryAmountFactory
around somewhere, but as mentioned above, MonetaryAmountFactory
isn't guaranteed to be thread safe.
Am I expected to resort to ThreadLocal
or something similar in my deserializer so I can keep a separate amount factory around per thread?
Note that the JavaxMoneyModule for Jackson (which I believe came from Zalando) completely ignores the admonition about thread safety, and keeps a MonetaryAmountFactory
around to be used by all deserialization, ignoring threads!
private <T extends MonetaryAmount> JavaxMoneyModule(final AmountWriter<?> writer, final FieldNames names, final MonetaryAmountFormatFactory formatFactory, final MonetaryAmountFactory<T> amountFactory) {
this.writer = writer;
this.names = names;
this.formatFactory = formatFactory;
this.amountFactory = amountFactory;
}
…
//Use provided amountFactory to deserialize a MonetaryAmount
deserializers.addDeserializer(MonetaryAmount.class, new MonetaryAmountDeserializer<>(amountFactory, names));
It would thus seem the Zalander/Jackson Java money module is blatantly ignoring the thread-safety of the MonetaryAmountFactory
(probably because, like me, the alternative seems unfathomable). But thread-safety isn't just something we can ignore.
How was this envisioned to be used in the real world?