Search code examples
javajpaspring-data-jpapostgis

How to handle table column of type that is not known in Java (Spring Data)?


I have a table with a column of type geography(Point,4326) (using PostGIS). I only need to use this column in the WHERE condition when querying the table. E.g. in the query below, geog is the name of that column.

@Query(value = "SELECT pois.*\n" +
        "FROM pois,\n" +
        "(select ST_MakePoint(:lat,:lon)::geography as poi) as poi\n" +
        "WHERE ST_DWithin(geog, poi, 400)\n" +
        "ORDER BY ST_Distance(geog, poi)", nativeQuery = true)
public List<PointOfInterest> getPOIsAroundLocation(@Param("lat") double lat,
                                                   @Param("lon") double lon);

However, in the entity class PointOfInterest, I don't know how to map that column, since I don't have a Java type equivalent to the geography(Point,4326) database type.

If I don't mention the column at all in the class, it won't be created in the database (I have spring.jpa.hibernate.ddl-auto=create), and the query will fail.

What can I do? Is there a way to create a column with a java type (maybe Object?) and then map it to the db type with some annotation? Or is there a way to tell Spring Data about the db column without actually adding a field I won't use in the class?

Here is the PointOfInterest class:

@Data
@Entity(name = "pois")
public abstract class PointOfInterest {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private final double latitude;
    private final double longitude;
    private final PoiType poiType;

    public PointOfInterest() {
        this.latitude = this.longitude = 0;
        poiType = null;
    }

    public PointOfInterest(double latitude, double longitude, PoiType poiType) {
        this.latitude = latitude;
        this.longitude = longitude;
        this.poiType = poiType;
    }
}

Solution

  • After I found out about hibernate-spatial from the comment of @Pilosa, I added some dependencies:

    <dependency>
        <groupId>org.locationtech.jts</groupId>
        <artifactId>jts-core</artifactId>
        <version>1.16.1</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-spatial</artifactId>
        <version>5.4.10.Final</version>
    </dependency>
    

    And I added a org.locationtech.jts.geom.Point field in the Entity class to map the geography column.

    @JsonIgnore
    @Column(columnDefinition = "geography(Point,4326)")
    private Point geog;
    

    The @JsonIgnore annotation is because jackson threw a stack overflow exception when trying to deserialize the field (see related question). This solution worked for me since I only use the point for querying, and I don't need its value.