GeoDesk for Java
| GeoDesk for Java | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Author: | Clarisma / GeoDesk contributors | |||||||||||||||||||
| License: | Apache License 2.0 | |||||||||||||||||||
| Version: | 2.0.0 (2025-09-29) | |||||||||||||||||||
| Language: | java
| |||||||||||||||||||
| Website: | https://docs.geodesk.com/java | |||||||||||||||||||
| Source code: | https://github.com/clarisma/geodesk | |||||||||||||||||||
|
Java SDK for querying and analyzing OpenStreetMap data stored in Geo-Object Libraries (GOLs) | ||||||||||||||||||||
| ||||||||||||||||||||
GeoDesk for Java is an open-source Java library for fast querying and analysis of OpenStreetMap data. It is part of the GeoDesk toolkit and provides a Java API for working with Geo-Object Libraries (GOLs) — compact spatial databases designed specifically for OSM data.
GeoDesk for Java is also available for Python and for C++.
Overview
GeoDesk for Java allows developers to build geospatial applications on Java 16 or above. It works directly with GOL files (no server process required) and provides a rich set of spatial query capabilities. Key characteristics include:
- Compact storage — GOL files are only 20% to 50% larger than OSM-PBF source data, less than a tenth of the storage consumed by a traditional SQL-based database.
- Fast queries — typically 50 times faster than SQL.
- Intuitive API — queries return Java objects. Quickly discover tags, way-nodes and relation members. Get a feature's geometry, measure its length/area.
- Full relation support — unlike traditional geospatial databases, GeoDesk natively handles relations, a unique and powerful aspect of OSM data.
- JTS integration — features can be converted to JTS (Java Topology Suite) geometries for advanced geometric operations such as buffer, union, simplify, convex hulls, and more.
- Automatic tile downloading — feature libraries can be configured to automatically fetch missing tiles from a remote repository as they are needed by queries.
- Thread-safe — the
FeatureLibraryobject is thread-safe and can be shared across multiple threads. GOL files can also be shared among multiple processes. - Modest hardware requirements — any 64-bit system with Java 16+ will run GeoDesk.
System Requirements
- Java 16 or above
- 64-bit system running Windows, macOS or Linux
- The GOL Tool is required to create or manage GOL files
Installation
Stable releases are available on Maven Central. Add the following dependency to your project's POM:
<dependency>
<groupId>com.geodesk</groupId>
<artifactId>geodesk</artifactId>
<version>2.0.0</version>
</dependency>
Alternatively, build the latest version from source:
git clone https://github.com/clarisma/geodesk.git
cd geodesk
mvn install
You also need the GOL Tool to build or manage GOL files. See the GOL Tool download page for installation instructions.
Getting Started
Creating a GOL
Before using GeoDesk for Java, you need a Geo-Object Library (GOL) containing OSM data. You can create one from any .osm.pbf file using the GOL Tool:
gol build germany germany-latest.osm.pbf
Country and regional extracts can be downloaded from sites such as GeoFabrik or BBBike. Alternatively, you can download pre-made data tiles from a Geo-Object Bundle (e.g. from Open Planet Data) using the gol load command.
Opening a Feature Library
import com.geodesk.feature.*;
import com.geodesk.geom.*;
FeatureLibrary germany = new FeatureLibrary("germany.gol");
The FeatureLibrary itself implements the Features interface, representing all features in the GOL.
To automatically download missing tiles as they are needed by queries, specify a repository URL:
FeatureLibrary world = new FeatureLibrary(
"world.gol", "https://data.geodesk.com/world");
When you are done querying, close the library to release its resources:
germany.close();
Querying Features
Features can be filtered using GOQL (Geo-Object Query Language), a concise query syntax similar to MapCSS:
Features restaurants = germany.select("na[amenity=restaurant]"); // Nodes and areas
Features hydrants = germany.nodes("[emergency=fire_hydrant]"); // Only nodes
Features highways = germany.ways("[highway]"); // Only ways
Features routes = germany.relations("[route=bicycle]"); // Only relations
The type selectors are: n (nodes), w (ways, excluding areas), a (areas, which can be ways or relations), r (relations, excluding areas), and * (any type).
Bounding Box Queries
Features can be restricted to a bounding box using the in() method:
Box bbox = Box.ofWSEN(8.42, 53.75, 9.07, 53.98);
// West, South, East, North as longitude/latitude
Features subset = germany.select("na[tourism=hotel]").in(bbox);
Spatial Queries
Features can be filtered spatially using methods like within(), intersecting(), containing(), crossing(), touching(), and maxMetersFrom():
// Find all museums within a city
Features parisMuseums = museums.within(paris);
// Find bus stops within 500 meters of a restaurant
Features nearbyStops = features.select("n[highway=bus_stop]")
.maxMetersFrom(500, restaurant);
// Find railway bridges crossing a river
Features bridges = features.select("w[railway][bridge]")
.crossing(mississippi);
// Find the administrative area containing a given point
Features areas = features.select(
"a[boundary=administrative][admin_level <= 6]")
.containingLonLat(-117.25, 32.99);
Spatial filters accept Feature, JTS Geometry, and PreparedGeometry objects.
Filters can be combined:
roads.ways("[bridge]").in(bbox).crossing(rhineRiver)
Working with Features
Each Feature object represents an OSM element (node, way, or relation). Feature objects are obtained via queries.
Tags
Tags are accessed using dedicated methods:
String name = feature.stringValue("name"); // empty string if absent
int speed = feature.intValue("maxspeed"); // 0 if absent or non-numeric
double height = feature.doubleValue("height");
if (feature.hasTag("highway")) { ... }
if (feature.hasTag("shop", "bakery")) { ... }
All tags can be retrieved and iterated:
Tags tags = feature.tags();
while (tags.next())
{
String key = tags.key();
String value = tags.stringValue();
}
// Or convert to a Map
Map<String, Object> tagMap = feature.tags().toMap();
Properties
Features expose the following key properties:
type()— returns aFeatureTypeenum (NODE,WAY, orRELATION)id()— the feature's numeric OSM ID (long)isNode(),isWay(),isRelation(),isArea()— type testslon(),lat()— WGS-84 coordinates (degrees)x(),y()— Mercator-projected coordinatesbounds()— the bounding box (aBox)area()— area in square meters (for polygonal features)length()— length in meters (for lineal features)toGeometry()— creates a JTS geometry (Point,LineString,Polygon,MultiPolygon, orGeometryCollection)
Related Features
nodes()— the nodes of a way (with optional GOQL filter)members()— the members of a relation (with optional GOQL filter)parents()— relations containing this feature, or ways to which a node belongsrole()— the role of a feature within a relation (if obtained via a member query)
These queries can be inverted using the topological filter methods nodesOf(), membersOf(), and parentsOf() on feature collections.
belongsTo(feature) checks whether a feature is a member of a specific relation or a node of a specific way, and belongsToRelation() checks whether a feature is a member of any relation.
Feature Collections
Feature collections implement the Features interface and behave like Java Collection classes, supporting size(), isEmpty(), contains(), toArray(), and iteration. Additional methods include:
// Iterate
for (Feature street : streets) { ... }
// Convert to a list
List<Feature> list = streets.toList();
// Get the first feature (or null if empty)
Feature city = france.select("n[place=city][name=Paris]").first();
// Count
int n = restaurants.size();
Feature collections are lightweight and lazy — features are only fetched when iterated or when a terminal operation such as toList() is called.
Example Code
Find all pubs in Zurich and print their names:
import com.geodesk.feature.*;
import com.geodesk.geom.*;
public class PubsExample
{
public static void main(String[] args)
{
FeatureLibrary switzerland = new FeatureLibrary("switzerland.gol");
for (Feature pub : switzerland
.select("na[amenity=pub]")
.in(Box.ofWSEN(8.53, 47.36, 8.55, 47.38)))
{
System.out.println(pub.stringValue("name"));
}
switzerland.close();
}
}
Find all movie theaters within 500 meters of a given point:
Features cinemas = features.select("na[amenity=cinema]")
.maxMetersFromLonLat(500, myLon, myLat);
Count the number of entrances of a building:
int numberOfEntrances = building.nodes("[entrance]").size();
Discover bus routes traversing a street:
for (Feature route : street.parents("[route=bus]"))
{
System.out.printf("- %s from %s to %s%n",
route.stringValue("ref"),
route.stringValue("from"),
route.stringValue("to"));
}
More examples can be found on GitHub.
Documentation
Full documentation is available at docs.geodesk.com/java, covering:
- Five-minute tutorial
- Feature Libraries — opening and managing GOLs
- Features — working with Feature objects, tags, geometry, and related features
- Queries & Collections — filtering, spatial and topological queries
- Utility Classes —
Box,Coordinate,Measure, and other helpers - GOQL query language
See Also
- GeoDesk — main article covering the overall toolkit and GOL Tool
- Geographic Object Library — the GOL file format
- GeoDesk for Python — the Python SDK
- GeoDesk for C++ — the C++ SDK
- Databases and data access APIs — other tools for accessing OSM data