A zero-dependency Java library that fetches real-time currency exchange rates from multiple providers. Works on Java 8 through Java 25+ with automatic runtime optimisations on newer JVMs.
- 165+ currencies — full ISO 4217 coverage via the
Currencyenum - 5 providers with automatic failover — if one API is down or rate-limited, the next one is tried transparently
- Zero runtime dependencies — ships as a plain JAR with no transitive dependencies to manage
- Multi-Release JAR — runs on Java 8+; automatically uses
HttpClient(Java 11+) and virtual threads (Java 21+) when available - Parallel queries on Java 21+ — all configured providers are queried simultaneously; you get the fastest response instead of waiting for sequential failures
- Opt-in rate caching — built-in thread-safe TTL cache reduces API calls and improves latency
- Immutable configuration —
Configis immutable and thread-safe, built viaConfigBuilder - Input validation — null currencies and missing API keys fail fast with clear error messages
- JPMS-ready —
Automatic-Module-Namemanifest entry for clean module-path usage - Android-compatible — Java 8 bytecode base works with Android (see Android section)
- Type-safe API — currency codes are an enum, not magic strings
Add the dependency:
Maven
<dependency>
<groupId>com.posadskiy</groupId>
<artifactId>currency-converter</artifactId>
<version>1.4.0</version>
</dependency>Gradle
implementation 'com.posadskiy:currency-converter:1.4.0'Scala SBT
libraryDependencies += "com.posadskiy" % "currency-converter" % "1.4.0"Initialise and use:
CurrencyConverter converter = new CurrencyConverter(
new ConfigBuilder()
.openExchangeRatesApiKey("YOUR_KEY")
.build()
);
double rate = converter.rate(Currency.USD, Currency.EUR);
System.out.println("USD -> EUR: " + rate);| Provider | Website | Free tier |
|---|---|---|
| CurrencyLayer | currencylayer.com | Yes |
| OpenExchangeRates | openexchangerates.org | Yes |
| Fixer | fixer.io | Yes |
| CurrencyFreaks | currencyfreaks.com | Yes |
| CurrencyConverterApi | currencyconverterapi.com | No |
All providers offer a free API key — sign up on their websites to obtain one.
Recommendation: configure at least two providers. The library automatically falls back to the next one if a provider is unavailable. On Java 21+ all providers are queried in parallel and the first successful response wins.
CurrencyConverter converter = new CurrencyConverter(
new ConfigBuilder()
.currencyConverterApiApiKey("KEY_1")
.currencyLayerApiKey("KEY_2")
.openExchangeRatesApiKey("KEY_3")
.fixerApiKey("KEY_4")
.currencyFreaksApiKey("KEY_5")
.build()
);// Any two currencies by enum (type-safe, IDE-autocomplete)
double rate = converter.rate(Currency.GBP, Currency.JPY);
// Convenience methods for common pairs
double usdToEur = converter.rateFromUsdToEuro();
double eurToUsd = converter.rateFromEuroToUsd();
// From/to a fixed currency
double usdToAnything = converter.rateFromUsd(Currency.CHF);
double anythingToUsd = converter.rateToUsd(Currency.BRL);
// String-based (for dynamic input)
double dynamic = converter.rate("USD", "EUR");Exchange rates don't change every millisecond — caching avoids redundant API calls and speeds up repeated lookups. Caching is off by default and must be enabled explicitly:
CurrencyConverter converter = new CurrencyConverter(
new ConfigBuilder()
.openExchangeRatesApiKey("YOUR_KEY")
.cacheTtlSeconds(300) // cache rates for 5 minutes
.build()
);The cache is thread-safe (ConcurrentHashMap-backed) and entries expire automatically after the configured TTL. Set cacheTtlSeconds(0) or omit the call to disable caching.
The Currency enum contains every ISO 4217 code: AED, AFN, ALL, AMD, ARS, AUD, BRL, BTC, CAD, CHF, CNY, EUR, GBP, HKD, INR, JPY, KRW, MXN, NOK, NZD, PLN, RUB, SEK, SGD, THB, TRY, UAH, USD, ZAR, and many more.
This library is packaged as a Multi-Release JAR. The JVM picks the best implementation automatically — no code changes needed on your side.
| JVM version | NetworkUtils |
CurrencyConvertService |
|---|---|---|
| Java 8-10 | HttpURLConnection (10 s timeouts) |
Sequential fallback |
| Java 11-20 | HttpClient (connection pooling, HTTP/2) |
Sequential fallback |
| Java 21+ | HttpClient |
Parallel (virtual threads, invokeAny) |
On Java 21+, all configured providers are queried simultaneously on virtual threads. The response time equals the fastest responding provider instead of accumulating the latency of any failed ones.
- Sign up for free on any of the supported providers.
- Copy the API key from your account dashboard.
- Pass it to
ConfigBuilder— you only need one to get started.
src/
├── main/
│ ├── java/ # Java 8 base layer (runs on all JVMs)
│ │ └── com/posadskiy/currencyconverter/
│ │ ├── CurrencyConverter.java # public entry point + optional cache
│ │ ├── config/ # immutable Config + ConfigBuilder
│ │ ├── enums/Currency.java # ISO 4217 enum
│ │ ├── service/ # sequential fallback + RateCache
│ │ ├── source/ # provider adapters (JSON-parsed)
│ │ └── util/ # NetworkUtils, JsonHelper
│ ├── java11/ # Java 11 override: HttpClient-based NetworkUtils
│ └── java21/ # Java 21 override: virtual-thread CurrencyConvertService
└── test/
└── java/ # Unit + integration tests (HttpServer stubs)
Key design decisions:
- Zero dependencies — a lightweight built-in JSON parser (
JsonHelper) avoids pulling in Jackson/Gson - Immutable config —
Confighas no setters; useConfigBuilderfor construction - Thread safety — all shared state is immutable or
ConcurrentHashMap-backed - Fail-fast validation — null currencies and invalid configs throw immediately
Android prohibits network calls on the main thread. Wrap the CurrencyConverter call in a background thread (e.g. AsyncTask, coroutine, or ExecutorService):
new Thread(() -> {
double rate = converter.rate(Currency.USD, Currency.EUR);
runOnUiThread(() -> textView.setText(String.valueOf(rate)));
}).start();Also add the Internet permission to AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET"/>Contributions are welcome! Here is how to get started:
- Fork the repository and create a branch:
git checkout -b feat/your-feature - Make your changes and add tests
- Build and verify:
mvn clean verify - Open a Pull Request — describe what you changed and why
- Implement
ConverterSource(one method:Double rate(String apiKey, Currency from, Currency to)) - Register the new source in
CurrencyConvertService.buildEntries()and the Java 21buildTasks() - Add an integration test in
src/test
# Requires JDK 21+ to compile all MR-JAR layers
mvn clean package
# Run all tests (deterministic — HTTP stubs, no real API calls)
mvn clean verify
# Run with real API keys (optional)
RUN_EXTERNAL_TESTS=true mvn clean verify -DCURRENCY_LAYER_KEY=your_key ...Currency Converter is available under the MIT License.