18. Spatial

18.1. Overview

Hibernate Spatial was originally developed as a generic extension to Hibernate for handling geographic data. Since 5.0, Hibernate Spatial is now part of the Hibernate ORM project, and it allows you to deal with geographic data in a standardized way.

Hibernate Spatial provides a standardized, cross-database interface to geographic data storage and query functions. It supports most of the functions described by the OGC Simple Feature Specification. Supported databases are Oracle 10g/11g, PostgreSQL/PostGIS, MySQL, Microsoft SQL Server and H2/GeoDB.

Spatial data types are not part of the Java standard library, and they are absent from the JDBC specification. Over the years JTS has emerged the de facto standard to fill this gap. JTS is an implementation of the Simple Feature Specification (SFS). Many databases on the other hand implement the SQL/MM - Part 3: Spatial Data specification - a related, but broader specification. The biggest difference is that SFS is limited to 2D geometries in the projected plane (although JTS supports 3D coordinates), whereas SQL/MM supports 2-, 3- or 4-dimensional coordinate spaces.

Hibernate Spatial supports two different geometry models: JTS and geolatte-geom. As already mentioned, JTS is the de facto standard. Geolatte-geom (also written by the lead developer of Hibernate Spatial) is a more recent library that supports many features specified in SQL/MM but not available in JTS (such as support for 4D geometries, and support for extended WKT/WKB formats). Geolatte-geom also implements encoders/decoders for the database native types. Geolatte-geom has good interoperability with JTS. Converting a Geolatte geometry to a JTS `geometry, for instance, doesn’t require copying of the coordinates. It also delegates spatial processing to JTS.

Whether you use JTS or Geolatte-geom, Hibernate spatial maps the database spatial types to your geometry model of choice. It will, however, always use Geolatte-geom to decode the database native types.

Hibernate Spatial also makes a number of spatial functions available in HQL and in the Criteria Query API. These functions are specified in both SQL/MM as SFS, and are commonly implemented in databases with spatial support (see Hibernate Spatial dialect function support)

18.2. Configuration

Hibernate Spatial requires some configuration prior to start using it.

18.2.1. Dependency

You need to include the hibernate-spatial dependency in your build environment. For Maven, you need to add the following dependency:

Example 632. Maven dependency

  1. <dependency>
  2. <groupId>org.hibernate</groupId>
  3. <artifactId>hibernate-spatial</artifactId>
  4. <version>${hibernate.version}</version>
  5. </dependency>

18.2.2. Dialects

Hibernate Spatial extends the Hibernate ORM dialects so that the spatial functions of the database are made available within HQL and JPQL. So, for instance, instead of using the PostgreSQL82Dialect, we use the Hibernate Spatial extension of that dialect which is the PostgisDialect.

Example 633. Specifying a spatial dialect

  1. <property
  2. name="hibernate.dialect"
  3. value="org.hibernate.spatial.dialect.postgis.PostgisDialect"
  4. />

Not all databases support all the functions defined by Hibernate Spatial. The table below provides an overview of the functions provided by each database. If the function is defined in the Simple Feature Specification, the description references the relevant section.

Table 10. Hibernate Spatial dialect function support

Function

Description

PostgresSQL

Oracle 10g/11g

MySQL

SQLServer

GeoDB (H2)

DB2

Basic functions on Geometry

int dimension(Geometry)

SFS §2.1.1.1

String geometrytype(Geometry)

SFS §2.1.1.1

int srid(Geometry)

SFS §2.1.1.1

Geometry envelope(Geometry)

SFS §2.1.1.1

String astext(Geometry)

SFS §2.1.1.1

byte[] asbinary(Geometry)

SFS §2.1.1.1

boolean isempty(Geometry)

SFS §2.1.1.1

boolean issimple(Geometry)

SFS §2.1.1.1

Geometry boundary(Geometry)

SFS §2.1.1.1

Functions for testing Spatial Relations between geometric objects

boolean equals(Geometry, Geometry)

SFS §2.1.1.2

boolean disjoint(Geometry, Geometry)

SFS §2.1.1.2

boolean intersects(Geometry, Geometry)

SFS §2.1.1.2

boolean touches(Geometry, Geometry)

SFS §2.1.1.2

boolean crosses(Geometry, Geometry)

SFS §2.1.1.2

boolean within(Geometry, Geometry)

SFS §2.1.1.2

boolean contains(Geometry, Geometry)

SFS §2.1.1.2

boolean overlaps(Geometry, Geometry)

SFS §2.1.1.2

boolean relate(Geometry, Geometry, String)

SFS §2.1.1.2

Functions that support Spatial Analysis

double distance(Geometry, Geometry)

SFS §2.1.1.3

Geometry buffer(Geometry, double)

SFS §2.1.1.3

Geometry convexhull(Geometry)

SFS §2.1.1.3

(1)

Geometry intersection(Geometry, Geometry)

SFS §2.1.1.3

(1)

Geometry geomunion(Geometry, Geometry)

SFS §2.1.1.3 (renamed from union)

(1)

Geometry difference(Geometry, Geometry)

SFS §2.1.1.3

(1)

Geometry symdifference(Geometry, Geometry)

SFS §2.1.1.3

(1)

Common non-SFS functions

boolean dwithin(Geometry, Geometry, double)

Returns true if the geometries are within the specified distance of one another

Geometry transform(Geometry, int)

Returns a new geometry with its coordinates transformed to the SRID referenced by the integer parameter

Spatial aggregate Functions

Geometry extent(Geometry)

Returns a bounding box that bounds the set of returned geometries

(1) Argument Geometries need to have the same dimensionality.

Postgis

For Postgis from versions 1.3 and later, the best dialect to use is org.hibernate.spatial.dialect.postgis.PostgisDialect.

This translates the HQL spatial functions to the Postgis SQL/MM-compliant functions. For older, pre v1.3 versions of Postgis, which are not SQL/MM compliant, the dialect org.hibernate.spatial.dialect.postgis.PostgisNoSQLMM is provided.

MySQL

There are several dialects for MySQL:

  • MySQLSpatialDialect

    a spatially-extended version of Hibernate MySQLDialect

    MySQL5SpatialDialect

    a spatially-extended version of Hibernate MySQL5Dialect

    MySQLSpatial56Dialect

    a spatially-extended version of Hibernate MySQL55Dialect.

MySQL versions before 5.6.1 had only limited support for spatial operators. Most operators only took account of the minimum bounding rectangles (MBR) of the geometries, and not the geometries themselves.

This changed in version 5.6.1, when MySQL introduced ST_* spatial operators. The dialect MySQLSpatial56Dialect uses these newer, more precise operators.

These dialects may, therefore, produce results that differ from that of the other spatial dialects.

For more information, see this page in the MySQL reference guide (esp. the section Functions That Test Spatial Relations Between Geometry Objects)

Oracle10g/11g

There is currently only one Oracle spatial dialect: OracleSpatial10gDialect which extends the Hibernate dialect Oracle10gDialect. This dialect has been tested on both Oracle 10g and Oracle 11g with the SDO_GEOMETRY spatial database type.

This dialect can be configured using the Hibernate property:

  • hibernate.spatial.connection_finder

    the fully-qualified class name for the implementation of the ConnectionFinder to use (see below).

The ConnectionFinder interface

The SDOGeometryType requires access to an OracleConnection object when converting a geometry to SDO_GEOMETRY. In some environments, however, the OracleConnection is not available (e.g. because a Java EE container or connection pool proxy wraps the connection object in its own Connection implementation). A ConnectionFinder knows how to retrieve the OracleConnection from the wrapper or proxy Connection object that is passed into prepared statements.

When the passed object is not already an OracleConnection, the default implementation will attempt to retrieve the OracleConnection by recursive reflection. It will search for methods that return Connection objects, execute these methods and check the result. If the result is of type OracleConnection the object is returned. Otherwise, it recurses on it.

In may cases, this strategy will suffice. If not, you can provide your own implementation of this interface on the classpath, and configure it in the hibernate.spatial.connection_finder property. Note that implementations must be thread-safe and have a default no-args constructor.

SQL Server

The dialect SqlServer2008Dialect supports the GEOMETRY type in SQL Server 2008 and later.

The GEOGRAPHY type is not currently supported.

GeoDB (H2)

The GeoDBDialect supports the GeoDB a spatial extension of the H2 in-memory database.

The dialect has been tested with GeoDB version 0.7

DB2

The DB2SpatialDialect supports the spatial extensions of the DB2 LUW database. The dialect has been tested with DB2 LUW 11.1. The dialect does not support DB2 for z/OS or DB2 column-oriented databases.

In order to use the DB2 Hibernate Spatial capabilities, it is necessary to first execute the following SQL statements which will allow DB2 to accept Extended WellKnown Text (EWKT) data and return EWKT data. One way to do this is to copy these statements into a file such as ewkt.sql and execute it in a DB2 command window with a command like ‘db2 -tvf ewkt.sql’.

  1. create or replace function db2gse.asewkt(geometry db2gse.st_geometry)
  2. returns clob(2G)
  3. specific db2gse.asewkt1
  4. language sql
  5. deterministic
  6. no external action
  7. reads sql data
  8. return srid=’ || varchar(db2gse.st_srsid(geometry)) || ‘;’ || db2gse.st_astext(geometry);
  9. create or replace function db2gse.geomfromewkt(instring varchar(32000))
  10. returns db2gse.st_geometry
  11. specific db2gse.fromewkt1
  12. language sql
  13. deterministic
  14. no external action
  15. reads sql data
  16. return db2gse.st_geometry(
  17. substr(instring,posstr(instring,’;’)+1, length(instring) - posstr(instring,’;’)),
  18. integer(substr(instring,posstr(instring,’=’)+1,posstr(instring,’;’)-(posstr(instring,’=’)+1))));
  19. create transform for db2gse.st_geometry ewkt (
  20. from sql with function db2gse.asewkt(db2gse.st_geometry),
  21. to sql with function db2gse.geomfromewkt(varchar(32000)) );
  22. drop transform db2_program for db2gse.st_geometry;
  23. create transform for db2gse.st_geometry db2_program (
  24. from sql with function db2gse.asewkt(db2gse.st_geometry),
  25. to sql with function db2gse.geomfromewkt(varchar(32000)) );

18.3. Types

Hibernate Spatial comes with the following types:

jts_geometry

Handled by org.hibernate.spatial.JTSGeometryType it maps a database geometry column type to a org.locationtech.jts.geom.Geometry entity property type.

geolatte_geometry

Handled by org.hibernate.spatial.GeolatteGeometryType, it maps a database geometry column type to an org.geolatte.geom.Geometry entity property type.

It suffices to declare a property as either a JTS or a Geolatte-geom Geometry and Hibernate Spatial will map it using the relevant type.

Here is an example using JTS:

Example 634. Type mapping

  1. import org.locationtech.jts.geom.Point;
  2. @Entity(name = "Event")
  3. public static class Event {
  4. @Id
  5. private Long id;
  6. private String name;
  7. private Point location;
  8. //Getters and setters are omitted for brevity
  9. }

We can now treat spatial geometries like any other type.

Example 635. Creating a Point

  1. Event event = new Event();
  2. event.setId( 1L);
  3. event.setName( "Hibernate ORM presentation");
  4. Point point = geometryFactory.createPoint( new Coordinate( 10, 5 ) );
  5. event.setLocation( point );
  6. entityManager.persist( event );

Spatial Dialects defines many query functions that are available both in HQL and JPQL queries. Below we show how we could use the within function to find all objects within a given spatial extent or window.

Example 636. Querying the geometry

  1. Polygon window = geometryFactory.createPolygon( coordinates );
  2. Event event = entityManager.createQuery(
  3. "select e " +
  4. "from Event e " +
  5. "where within(e.location, :window) = true", Event.class)
  6. .setParameter("window", window)
  7. .getSingleResult();