Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Map a PostGIS geometry point field with Hibernate on Spring Boot

Tags:

In my PostgreSQL 9.3 + PostGIS 2.1.5 I have a table PLACE with a column coordinates of type Geometry(Point,26910).

I want to map it to Place entity in my Spring Boot 1.1.9 web application, which uses Hibernate 4.0.0 + . Place is available with a REST repository.

Unfortunately when I GET http://localhost:8080/mywebapp/places I receive this strange JSON response:

{    "_embedded" : {      "venues" : [ {        "id" : 1,        "coordinates" : {          "envelope" : {            "envelope" : {              "envelope" : {                "envelope" : {                  "envelope" : {                    "envelope" : {                      "envelope" : {                        "envelope" : {                          "envelope" : {                            "envelope" : {                              "envelope" : {                                "envelope" : {                                  "envelope" : {                                    "envelope" : {                                      "envelope" : {                                        "envelope" : {                                          "envelope" : {                                            "envelope" : {                                              "envelope" : { 

and so on indefinetely...! Spring log doesn't help..

I'm working with this application.properties:

spring.jpa.database-platform=org.hibernate.spatial.dialect.postgis.PostgisDialect spring.jpa.show-sql=false spring.jpa.hibernate.ddl-auto=update  spring.datasource.url=jdbc:postgresql://192.168.1.123/mywebapp spring.datasource.username=postgres spring.datasource.password=mypwd spring.datasource.driverClassName=org.postgresql.Driver 

First of all, is it ok to use database-platform instead of database? And maybe do I have to use following settings instead of the above?

spring.datasource.url=jdbc:postgresql_postGIS://192.168.1.123/mywebapp spring.datasource.driverClassName=org.postgis.DriverWrapper 

Anyway my entity is something like this:

@Entity public class Place {     @Id     public int id;     @Column(columnDefinition="Geometry")     @Type(type="org.hibernate.spatial.GeometryType")    //"org.hibernatespatial.GeometryUserType" seems to be for older versions of Hibernate Spatial     public com.vividsolutions.jts.geom.Point coordinates; } 

My pom.xml contains this relevant part:

<dependency>     <groupId>org.postgresql</groupId>     <artifactId>postgresql</artifactId>     <version>9.3-1102-jdbc41</version> </dependency> <dependency>     <groupId>org.hibernate</groupId>     <artifactId>hibernate-spatial</artifactId>     <version>4.3</version><!-- compatible with Hibernate 4.3.x -->     <exclusions>         <exclusion>             <artifactId>postgresql</artifactId>             <groupId>postgresql</groupId>         </exclusion>     </exclusions> </dependency> 

A bit strange configuration, I found it on the internet, it is the one that works best for now.

I hope that someone could help me with this mistery. :)

like image 539
bluish Avatar asked Dec 23 '14 17:12

bluish


1 Answers

Finally I discovered that my configuration is ok and might be Jackson that cannot manage Point data type correctly. So I customized its JSON serialization and deserialization:

  • add these annotations to our coordinates field:

    @JsonSerialize(using = PointToJsonSerializer.class) @JsonDeserialize(using = JsonToPointDeserializer.class) 
  • create such serializer:

    import java.io.IOException; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import com.vividsolutions.jts.geom.Point;  public class PointToJsonSerializer extends JsonSerializer<Point> {      @Override     public void serialize(Point value, JsonGenerator jgen,             SerializerProvider provider) throws IOException,             JsonProcessingException {          String jsonValue = "null";         try         {             if(value != null) {                              double lat = value.getY();                 double lon = value.getX();                 jsonValue = String.format("POINT (%s %s)", lat, lon);             }         }         catch(Exception e) {}          jgen.writeString(jsonValue);     }  } 
  • create such deserializer:

    import java.io.IOException; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.PrecisionModel;  public class JsonToPointDeserializer extends JsonDeserializer<Point> {      private final static GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(), 26910);       @Override     public Point deserialize(JsonParser jp, DeserializationContext ctxt)             throws IOException, JsonProcessingException {          try {             String text = jp.getText();             if(text == null || text.length() <= 0)                 return null;              String[] coordinates = text.replaceFirst("POINT ?\\(", "").replaceFirst("\\)", "").split(" ");             double lat = Double.parseDouble(coordinates[0]);             double lon = Double.parseDouble(coordinates[1]);              Point point = geometryFactory.createPoint(new Coordinate(lat, lon));             return point;         }         catch(Exception e){             return null;         }     }  } 

Maybe you can also use this serializer and this deserializer, available here.

like image 186
bluish Avatar answered Sep 21 '22 14:09

bluish