2014-12-23 12 views
15

Nel mio PostgreSQL 9.3 + PostGIS 2.1.5 ho una tabella con una colonna coordinates di tipo Geometry(Point,26910).Mappare un campo punto geometria PostGIS con Hibernate su Spring Boot

Desidero mapparlo all'entità Place nell'applicazione Web Spring Boot 1.1.9, che utilizza Hibernate 4.0.0 +. Place è disponibile con un repository REST.

Purtroppo quando ho GET http://localhost:8080/mywebapp/places ricevo questa risposta JSON strana:

{ 

    "_embedded" : { 

    "venues" : [ { 

     "id" : 1, 

     "coordinates" : { 

     "envelope" : { 

      "envelope" : { 

      "envelope" : { 

       "envelope" : { 

       "envelope" : { 

        "envelope" : { 

        "envelope" : { 

         "envelope" : { 

         "envelope" : { 

          "envelope" : { 

          "envelope" : { 

           "envelope" : { 

           "envelope" : { 

            "envelope" : { 

            "envelope" : { 

             "envelope" : { 

             "envelope" : { 

              "envelope" : { 

              "envelope" : { 

e così via indefinetely ...! log molla non aiuta ..

Sto lavorando con questa 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 

Prima di tutto, è ok per utilizzare al posto di database-platformdatabase? E forse devo usare le seguenti impostazioni al posto di quanto sopra?

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

Comunque il mio soggetto è qualcosa di simile:

@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; 
} 

mio pom.xml contiene questa parte rilevante:

<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> 

Una strana configurazione di bit, l'ho trovato su internet, è quello che funziona meglio per ora.

Spero che qualcuno possa aiutarmi con questo mistero. :)

risposta

15

Finalmente ho scoperto che la mia configurazione è ok e potrebbe essere Jackson che non può gestire Point tipo di dati in modo corretto. Così ho personalizzato la sua serializzazione JSON e deserializzazione:

  • aggiungere queste annotazioni al nostro coordinates campo:

    @JsonSerialize(using = PointToJsonSerializer.class) 
    @JsonDeserialize(using = JsonToPointDeserializer.class) 
    
  • creare tali serializzatore:

    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); 
        } 
    
    } 
    
  • creare tali deserializzatore:

    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; 
         } 
        } 
    
    } 
    

Forse si può anche utilizzare this serializer e this deserializer, disponibili here.

+0

Si noti che la latitudine e la longitudine di uscita dal Serializer vengono scambiate. è previsto? Questo codice lo spiega 'double lat = value.getX();' e 'double lon = value.getX();' grazie – randytan

+0

@randytan Ho usato questo codice molto tempo fa, ma ricordo che latitudine e longitudine dove nel giusto ordine. Dove li vedi scambiati? – bluish

+0

Se si invia 'POINT (AB)' e si esegue 'sys.out' alla variabile' jsonValue = String.format ("POINT (% s% s)", lat, lon); 'si può vedere che in realtà è stato scritto per 'POINT (BA)'. Ho appena scambiato il codice 'value.getY()' e 'value.getX()' per correggere la posizione. Grazie – randytan

0

Il problema non sembra essere correlato a PostgreSQL. Sembra che il tuo POJO abbia un backreference, il che significa che il tuo mappatore non sa come gestirlo. È necessario definire esplicitamente le relazioni ricorsive in modo che il mappatore sappia quando fermarsi. (Il mio legame Goto ->http://vard-lokkur.blogspot.com/2010/10/json-jackson-to-rescue.html)

+0

Avere alcun riferimento a qualsiasi altra entità, non è questo il problema. Grazie lo stesso! – bluish

1

Le soluzioni di cui sopra mi ha aiutato a risolvere il problema. Lo semplifico in modo che altre persone possano capire.

ho incluso questa biblioteca nel mio pom.xml:

<dependency> 
    <groupId>com.bedatadriven</groupId> 
    <artifactId>jackson-datatype-jts</artifactId> 
    <version>2.2</version> 
</dependency> 

Questo è l'oggetto POJO che ho usato. Poi sono stato in grado di far funzionare la chiamata REST senza l'errore di busta e le coodine appropriate.

import com.bedatadriven.jackson.datatype.jts.serialization.GeometryDeserializer; 
import com.bedatadriven.jackson.datatype.jts.serialization.GeometrySerializer; 
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 
import com.fasterxml.jackson.databind.annotation.JsonSerialize; 
import com.vividsolutions.jts.geom.Geometry; 

@Entity 
@Table(name = "boundary") 
public class Boundary { 

    private int id; 
    private Geometry geomertry; 

    @Id 
    public int getId() { 
     return ogc_fid; 
    } 

    public void setId(int id) { 
     this.id = id; 
    } 

    @JsonSerialize(using = GeometrySerializer.class) 
    @JsonDeserialize(using = GeometryDeserializer.class) 
    @Column(name = "geometry", columnDefinition = "Geometry") 
    public Geometry getGeomertry() { 
     return geomertry; 
    } 

    public void setGeomertry(Geometry geomertry) { 
     this.geomertry = geomertry; 
    } 
} 

mio tavolo aveva queste 2 colonne:

id  | integer    
geometry | geometry(Geometry,4326) | 
Problemi correlati