Сопоставьте поле точки геометрии PostGIS с Hibernate на Spring Загрузка

В моем PostgreSQL 9.3 + PostGIS 2.1.5 у меня есть таблица PLACE со столбцом coordinates типа Geometry(Point,26910).

Я хочу привязать его к объекту PLACE в моем веб-приложении Spring Boot 1.1.9, которое использует Hibernate 4.0.0+. PLACE доступен в репозитории REST.

К сожалению, когда я GET http://localhost:8080/mywebapp/places, я получаю этот странный ответ JSON:

{

  "_embedded" : {

    "venues" : [ {

      "id" : 1,

      "coordinates" : {

        "envelope" : {

          "envelope" : {

            "envelope" : {

              "envelope" : {

                "envelope" : {

                  "envelope" : {

                    "envelope" : {

                      "envelope" : {

                        "envelope" : {

                          "envelope" : {

                            "envelope" : {

                              "envelope" : {

                                "envelope" : {

                                  "envelope" : {

                                    "envelope" : {

                                      "envelope" : {

                                        "envelope" : {

                                          "envelope" : {

                                            "envelope" : {

и так далее неопределенно...! Spring журнал не помогает..

Я работаю с этим 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

Во-первых, можно ли использовать database-platform вместо database? И, возможно, мне нужно использовать следующие настройки вместо вышеуказанного?

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

В любом случае моя сущность выглядит примерно так:

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

Мой pom.xml содержит эту важную часть:

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

Немного странная конфигурация, я нашел его в Интернете, это тот, который работает лучше всего на данный момент.

Я надеюсь, что кто-то может помочь мне с этим мистерием.:)

Ответы

Ответ 1

Наконец, я обнаружил, что моя конфигурация в порядке и может быть Jackson, которая не может правильно управлять типом данных Point. Поэтому я настроил сериализацию и десериализацию JSON:

  • добавьте эти аннотации в наше поле coordinates:

    @JsonSerialize(using = PointToJsonSerializer.class)
    @JsonDeserialize(using = JsonToPointDeserializer.class)
    
  • создайте такой сериализатор:

    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);
        }
    
    }
    
  • создайте такой десериализатор:

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

Возможно, вы также можете использовать этот сериализатор и этот десериализатор, доступный .

Ответ 3

Вышеупомянутые решения помогли мне решить проблему. Я упрощаю это, чтобы другие люди могли понять.

Я включил эту библиотеку в свой pom.xml:

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

Это объект POJO, который я использовал. Затем мне удалось заставить вызов REST работать без ошибки конверта и правильных языков.

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

В моей таблице были два столбца:

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

Ответ 4

Проблема не связана с PostgreSQL. Похоже, ваш POJO имеет обратную ссылку, что означает, что ваш картограф не знает, как с ним справиться. Вам нужно явно определить рекурсивные отношения, чтобы диспетчер знал, когда остановиться. (Ссылка на мой Goto → http://vard-lokkur.blogspot.com/2010/10/json-jackson-to-rescue.html)