„Eine Investition in Wissen bringt noch immer die besten Zinsen.“
Benjamin Franklin
Nicht jeder JSR schafft es direkt ins JDK und dann vergisst man schon einmal, das seit 2015 eine Referenzimplementierung für Java Money existiert. Wer mit Geldbeträgen und Währungen nicht mehr direkt auf BigDecimal
arbeiten möchte, sollte sich deshalb unbedingt Moneta anschauen.
Moneta bietet die Möglichkeit mit Währungen zu arbeiten, mit Geldbeträge zu rechnen, das Runden von Geldbeträgen, die Währungsumrechnung nach Wechselkurs, Formatieren und Parsen von Geldbeträgen. Aber der Reihe nach.
Um mit Moneta arbeiten zu können, benötigt man die entsprechende Bibliothek im eigenen Projekt. Für Maven also einfach die folgende Dependency in die pom.xml
einfügen.
<dependency> <groupId>org.javamoney</groupId> <artifactId>moneta</artifactId> <version>1.4.1</version> <type>pom</type> </dependency>
Danach kann man mit Währungen und Beträgen arbeiten. Währungen werden über das Interface CurrencyUnit
dargestellt. Eine CurrencyUnit
kann über die Monetary
Factory erzeugt werden.
CurrencyUnit eur = Monetary.getCurrency("EUR"); CurrencyUnit jpy = Monetary.getCurrency(Locale.JAPAN); Collection<CurrencyUnit> all = Monetary.getCurrencies();
Im obigen Beispiel werden CurrencyUnit
Instanzen über den ISO Code, dem Länder Locale
oder über die Liste aller verfügbarer Währungen geholt. Wer eine nicht unterstützte Währung braucht, kann diese über den ServiceLoader
Mechanismus mit Hilfe eines CurrencyProviderSpi
erzeugen.
Geldbeträge werden mit dem Interface MonetaryAmount
repräsentiert. Erzeugt werden auch diese über Factory-Methoden.
MonetaryAmount moneyEur = Monetary.getDefaultAmountFactory().setCurrency(eur).setNumber(19.99).create(); MonetaryAmount moneyJpy = Monetary.getDefaultAmountFactory().setCurrency("JPY").setNumber(19.99).create();
Sind die Geldbeträge erzeugt, dann kann mit ihnen gerechnet werden.
MonetaryAmount tenPercent= MonetaryOperators.percent(10).apply(Money.of(1.99, "EUR")); MonetaryAmount amount = moneyEur.add(tenPercent);
Neben den hier dargestellten Methoden zur Berechnung eines prozentualen Betrages und der Addition von zwei Beträgen gibt es noch diverse andere Methoden. Da wären Promillebeträge, Subtraktion, Division und Multiplikation mit einer Zahl, Vergleichsmethoden und Kollektoren für die Stream-Verarbeitung.
MonetaryAmountFactory<Money> euroAmountFactory = Monetary.getDefaultAmountFactory().setCurrency("EUR"); MonetarySummaryStatistics statistic = IntStream.rangeClosed(1, 1000).mapToObj(x -> euroAmountFactory.setNumber(x).create()) .collect(MonetaryFunctions.summarizingMonetary(eur));
Der hier dargestellte Sourcecode erstellt 1000 Beträge von 1€ bis 1000€ und sammelt die Ergebnisse in der statistic
Variable. Der entsprechende Collector ähnelt dem ExtremaCollector aus dem Beitrag Extremes aus dem Stream, der auch mehrere Eigenschaften des Streams einsammelte. Über die Variable statistic
sind dann Min- und Max-Wert (1€ bzw. 1000€), die Summe (500500€) und der Durchschnitt (500,50$) zugreifbar.
Die Summe entspricht übrigens der tausensten Dreieckzahl, die nach der Gaußformel \frac{n^2 + n}{2} berechnet werden kann.
Erfreulicherweise wird die Klasse MonetaryAmount in diversen Frameworks schon unterstützt. So können Attribute von diesem Type mit Java Bean Validation Annotationen geprüft werden.
@Positive private MonetaryAmount price;
Diese @Positive
Annotation prüft den übergebenen Preis auf einen positiven Wert. Negative Geldbeträge oder etwas umsonst gibt es nicht. Mit der @PositiveOrZero
Annotation sind dann beispielsweise auch geschenkte Gäule gestattet.
Auch für die REST Schnittstelle gibt es Unterstützung in Form des jackson-datatype-money
Moduls. In Spring Boot reicht die entsprechende Zalando Dependency.
<dependency> <groupId>org.zalando</groupId> <artifactId>jackson-datatype-money</artifactId> <version>1.3.0</version> </dependency>
Danach noch etwas Code für die Konfiguration des ObjectMappers
.
@Bean public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() { return builder -> builder.postConfigurer(o -> o.registerModule(new MoneyModule().withDefaultFormatting())); }
Danach liefert der REST Endpunkt für MonetaryAmount
Attribute die folgende Ausgabe.
"price": { "amount": 9.95, "currency": "EUR", "formatted": "9,95 EUR" }
Ohne den Aufruf von withDefaultFormatting
würde in der Ausgabe das Attribut formatted
fehlen.
Ein Highlight der Bibliothek darf in diesem Beitrag natürlich nicht fehlen. Mit Moneta können auch Währungsumrechnungen einfach und aktuell durchgeführt werden.
ExchangeRateProvider rateProvider = MonetaryConversions.getExchangeRateProvider("ECB"); ExchangeRate chfToUsdRate = rateProvider.getExchangeRate("CHF", "EUR"); System.out.println(chfToUsdRate.getFactor());
Der ExchangeRateProvider
stellt die Daten für die Währungsumrechnungen bereit. Die im Beispiel angeforderte ExchangeRate für die Umrechnung von Schweizer Franken in Euro wird dabei direkt von Der EZB geholt und in der dritten Zeile als 1,014095933475307 ausgegeben.
Damit ist die Vorstellung der JSR 354 Implementierung Moneta auch schon wieder am Ende angekommen und jetzt viel Spaß beim Geld zählen!
1 thought on “JSR 354 – Ihre Nummer fürs Geld”