SkillAgentSearch skills...

Location4j

A Java library for efficient geographical lookups without external APIs. 🌎 Provides country, state, and city identification from free text with a built-in dataset.

Install / Use

/learn @tomaytotomato/Location4j

README

location4j 🌎4️⃣♨️

Build Status Bugs Quality Gate Status javadoc GitHub commit activity GitHub License libs.tech recommends

location4j is a simple Java library designed for efficient and accurate geographical data lookups for countries, states, and cities. πŸ—ΊοΈ

Unlike other libraries, it operates without relying on third-party APIs, making it both cost-effective and fast. 🏎️

Its built-in dataset provides quick lookups and no need for external HTTP calls. πŸ“€

Requirements πŸ“‹

  • Java 21 or higher (uses JPMS and Java 21 features)
  • Maven 3.8+ (for building from source)

Setup πŸš€

Get the latest version of the location4j library by adding it to your Maven pom.xml


<dependency>
    <groupId>com.tomaytotomato</groupId>
    <artifactId>location4j</artifactId>
    <version>1.0.6</version>
</dependency>

Gradle

implementation group: 'com.tomaytotomato', name: 'location4j', version: '1.0.6'

Quick Example πŸ—

import com.tomaytotomato.location4j.model.search.CityResult;
import com.tomaytotomato.location4j.model.search.CountryResult;
import com.tomaytotomato.location4j.model.search.SearchLocationResult;
import com.tomaytotomato.location4j.model.search.StateResult;
import com.tomaytotomato.location4j.usecase.search.SearchLocationService;

import java.util.List;

public class QuickExample {

  public static void main(String[] args) {
    SearchLocationService searchLocationService = SearchLocationService.builder().build();

    // Find all locations named San Francisco
    printResults(searchLocationService.search("san francisco"));

    // Narrow search to the US
    printResults(searchLocationService.search("san francisco, us"));

    // Narrow search further to California
    printResults(searchLocationService.search("san francisco, us california"));
  }

  private static void printResults(List<SearchLocationResult> results) {
    System.out.println("Locations found: " + results.size());

    results.forEach(result -> {
      switch (result) {
        case CountryResult country -> System.out.println("Country: " + country.name());
        case StateResult state -> System.out.println("State: " + state.country().name() + "/" + state.name());
        case CityResult city -> System.out.println("City: " + city.country().name() + "/" + city.state().name() + "/" + city.name());
      }
    });
  }
}

Features πŸ”¬

| Feature | Supported | Object | Example | |--------------------------------------------|-----------|----------|---------------------------------------------------------------------------------| | Search (free text) | βœ… | Location | search("kyiv") -> "Kyiv, Ukraine, Europe, UA" | | Find All Countries | βœ… | Country | findAllCountries() -> ["Belgium", "Canada", ...] | | Find Country by Id | βœ… | Country | findCountryById(1) -> ["Afghanistan"] | | Find Country by ISO2 code | βœ… | Country | findCountryByISO2Code("CA") -> ["Canada"] | | Find Country by ISO3 code | βœ… | Country | findCountryByISO3Code("CAN") -> ["Canada"] | | Find Country by Name | βœ… | Country | findCountryByName("Canada") -> ["Canada"] | | Find Country by Localised name | βœ… | Country | findCountryByLocalisedName("Belgique") -> ["Belgium"] | | Find Countries by State name | βœ… | Country | findAllCountriesByStateName("Texas") -> ["USA"] | | Find States by State name | βœ… | State | findAllStatesByStateName("Texas") -> ["Texas", "USA"] | | Find State by State Id | βœ… | State | findStateById(5) -> ["California", "USA"] | | Find States by State code | βœ… | State | findAllStatesByStateCode("CA") -> ["California", "USA"] | | Find City by City Id | βœ… | City | findCityById(10) -> ["Los Angeles", "California"] | | Find All Cities | βœ… | City | findAllCities() -> [All cities in database] | | Find Cities by City name | βœ… | City | findAllCitiesByCityName("San Francisco") -> ["San Francisco", "California"] | | Find Closest City by latitude/longitude | βœ… | City | findClosestCityByLatLong(30.438, -84.280) -> ["Tallahassee", "Florida"] | | Find Closest City by BigDecimal lat/long | βœ… | City | findClosestCityByLatLong(new BigDecimal("30.438"), new BigDecimal("-84.280")) | | Find Closest City by String lat/long | βœ… | City | findClosestCityByLatLong("30.438", "-84.280") -> ["Tallahassee", "Florida"] | | Find Street or Address | ❌ | N/A | Not supported - location4j does not provide street-level details | | Find Zipcode/Postcode | ❌ | N/A | Not supported - location4j does not include postal code data | | Find Small Towns/Villages | ❌ | N/A | Not supported - location4j focuses on major cities and administrative divisions |

ℹ️ location4j can parse free text strings with or without punctuation or capitalisation e.g.

San Francisco, CA, USA

ca united states san francisco

US, San Francisco, california

More Examples πŸ§ͺ

Lookup countries

For simple lookups the LocationService can act like a repository, allow the retrieval of countries, states and city information.


import com.tomaytotomato.location4j.model.lookup.City;
import com.tomaytotomato.location4j.model.lookup.Country;
import com.tomaytotomato.location4j.usecase.lookup.LocationService;

import java.util.List;
import java.util.Optional;

public class LocationServiceExample {

  public static void main(String[] args) {
    LocationService locationService = LocationService.builder().build();

    // Get all countries
    List<Country> countries = locationService.findAllCountries();

    // Filter European countries
    List<Country> europeanCountries = countries.stream()
      .filter(country -> "Europe".equals(country.getRegion()))
      .toList();

    // Find Afghanistan by ID
    Optional<Country> afghanistan = locationService.findCountryById(1);

    // Find all cities named San Francisco
    List<City> cities = locationService.findAllCitiesByCityName("San Francisco");
  }
}

Search locations

Search any text for a location, the SearchLocationService can handle formatted or unformatted text. It will try and find matches against a variety of keywords it has in its dataset.


import com.tomaytotomato.location4j.model.search.SearchLocationResult;
import com.tomaytotomato.location4j.text.normaliser.DefaultTextNormaliser;
import com.tomaytotomato.location4j.usecase.search.SearchLocationService;

import java.util.List;

public class SearchLocationServiceExample {

  public static void main(String[] args) {
    SearchLocationService searchLocationService = SearchLocationService.builder()
      .withTextNormaliser(new DefaultTextNormaliser())
      .build();

    // Search for Santa Clara
    List<SearchLocationResult> results = searchLocationService.search("Santa Clara");

    // Search for Santa Clara in the USA
    List<SearchLocationResult> resultsUnitedStates = searchLocationService.search("Santa Clara USA");

    // Search for Santa Clara in California (it works with ISO2 or ISO3) codes
    List<SearchLocationResult> resultsCalifornia = searchLocationService.search("Santa Clara US CA");
  }
}

Motivation 🌱

Parsing location data efficiently is crucial for many applications, yet it can be complex and time-consuming.

Third-party services like Google Location API can be costly, and using large language models can introduce significant latency.

location4j offers a practical solution with its own dataset, enabling fast and cost-effective geographical lookups to a city/town level (which is sufficient in most cases).

This allows applications to be built without another external dependency and the overheads that come with it.

I may add other functionality in the future if needed e.g. geolocation to nearest place, geofencing etc.

More Info

Testing Development Build Tools

Credits πŸ™

Country data sourced from dr5shn/countries-states-cities-database [License: ODbL](https://opendatacommons.org/licenses/odbl/

Related Skills

View on GitHub
GitHub Stars63
CategoryDevelopment
Updated15d ago
Forks5

Languages

Java

Security Score

100/100

Audited on Mar 15, 2026

No findings