A Java 17+ client for the Demografix demographic-prediction APIs — genderize.io, agify.io, and nationalize.io. Predict the gender, age, and nationality most commonly associated with a first name.
This is an unofficial port of the Python and PHP clients, built for JVM projects.
- Java 17+
- One small dependency (Gson)
- Immutable, thread-safe client
- Typed exceptions and quota reporting
- Single and batch (up to 10 names) requests
<dependency>
<groupId>ca.int13.demografix</groupId>
<artifactId>demografix</artifactId>
<version>1.0.0</version>
</dependency>implementation 'ca.int13.demografix:demografix:1.0.0'import ca.int13.demografix.Demografix;
import ca.int13.demografix.model.*;
// Keyless — subject to the free shared daily quota:
Demografix client = Demografix.create();
// Or authenticate with an API key (one key works across all three services):
Demografix client = Demografix.builder().apiKey("YOUR_API_KEY").build();
GenderizeResult g = client.genderize("peter");
g.getGender().ifPresent(gender ->
System.out.println(gender + " (" + g.getProbability() + ")")); // MALE (0.99)
AgifyResult a = client.agify("peter");
a.getAge().ifPresent(age -> System.out.println("~" + age + " years old")); // ~61 years old
NationalizeResult n = client.nationalize("peter");
n.getTopCountry().ifPresent(c ->
System.out.println(c.getCountryId() + " " + c.getProbability())); // UA 0.15The client is immutable and thread-safe — build one and reuse it across your application.
An API key is optional but recommended. Sign up at any of genderize.io, agify.io, or nationalize.io; a single key works across all three services. Without a key the APIs still respond, but with a smaller shared daily quota.
Demografix client = Demografix.withApiKey("YOUR_API_KEY");GenderizeResult r = client.genderize("emma");
r.getName(); // "emma"
r.getGender(); // Optional<Gender> — MALE, FEMALE, or empty if undetermined
r.getRawGender(); // "female" (or null)
r.getProbability(); // 0.0 – 1.0
r.getCount(); // number of data rows behind the predictionAgifyResult r = client.agify("emma");
r.getAge(); // Optional<Integer>
r.getCount();NationalizeResult r = client.nationalize("emma");
r.getCountries(); // List<CountryPrediction>, ordered by descending probability
r.getTopCountry(); // Optional<CountryPrediction>
for (CountryPrediction c : r.getCountries()) {
System.out.println(c.getCountryId() + " -> " + c.getProbability());
}genderize and agify accept an optional ISO 3166-1 alpha-2 country code to bias the
prediction toward a region:
client.genderize("andrea", "IT"); // in Italy, more likely male
client.agify("andrea", "US");Each method has a batch variant that accepts up to 10 names in a single HTTP call:
List<GenderizeResult> genders = client.genderizeBatch(List.of("michael", "jane"));
List<AgifyResult> ages = client.agifyBatch(List.of("michael", "jane"));
List<NationalizeResult> origins = client.nationalizeBatch(List.of("michael", "jane"));Passing more than 10 names (or an empty list) throws IllegalArgumentException.
Every result exposes the request quota reported by the response headers:
Quota q = client.genderize("peter").getQuota();
q.getLimit(); // Optional<Integer> — requests allowed this window
q.getRemaining(); // Optional<Integer> — requests left
q.getResetSeconds(); // Optional<Integer> — seconds until the window resetsQuota fields are only populated on authenticated requests; a keyless call returns an empty quota.
All errors extend DemografixException:
| Exception | Cause |
|---|---|
AuthException |
HTTP 401 — missing or invalid API key |
SubscriptionException |
HTTP 402 — subscription not active |
ValidationException |
HTTP 422 — invalid request parameters |
RateLimitException |
HTTP 429 — quota exhausted (getResetSeconds()) |
DemografixApiException |
any other non-success status (getStatusCode()) |
TransportException |
network failure, timeout, or unparseable response |
try {
client.genderize("peter");
} catch (RateLimitException e) {
System.out.println("Retry in " + e.getResetSeconds() + "s");
} catch (DemografixException e) {
System.err.println("Demografix call failed: " + e.getMessage());
}Client-side programming errors (null/blank names, oversized batches) throw
IllegalArgumentException / NullPointerException before any request is made.
Demografix client = Demografix.builder()
.apiKey("YOUR_API_KEY")
.connectTimeout(Duration.ofSeconds(5))
.requestTimeout(Duration.ofSeconds(15))
.userAgent("my-app/1.0")
.httpClient(myHttpClient) // optional: supply your own java.net.http.HttpClient
.build();mvn clean verifyRequires JDK 17 or newer. The build produces the main jar plus -sources and -javadoc jars.