Map a PostGIS geometry point field with Hibernate on Spring Boot

前端 未结 5 639
忘掉有多难
忘掉有多难 2020-12-24 07:30

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 m

相关标签:
5条回答
  • 2020-12-24 07:57

    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.

    0 讨论(0)
  • 2020-12-24 07:57

    The solutions above helped me to fix the problem. I simplify it so other people can understand.

    I included this library in my pom.xml:

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

    This is the POJO object I used. Then I was able to get the REST call to work without the envelope error and proper coodinates.

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

    My table had these 2 columns:

    id       | integer            
    geometry | geometry(Geometry,4326) | 
    
    0 讨论(0)
  • 2020-12-24 07:58

    The problem doesn't appear to be related to PostgreSQL. It appears that your POJO has a backreference, which means that your mapper doesn't know how to handle it. You need to explicitly define the recursive relationships so that the mapper knows when to stop. (My Goto link --> http://vard-lokkur.blogspot.com/2010/10/json-jackson-to-rescue.html)

    0 讨论(0)
  • 2020-12-24 08:00

    This serialization/deserialization also worked fine for me.

    https://github.com/bedatadriven/jackson-datatype-jts

    0 讨论(0)
  • 2020-12-24 08:03

    If you don't want to add the annotation on all your fields that are using a Point, you can also use the @JsonComponent to register your JsonSerializer and JsonDeserializer.

    @JsonComponent
    public class PointSerializer extends JsonSerializer<com.vividsolutions.jts.geom.Point>{
    
        @Override
     public void serialize(com.vividsolutions.jts.geom.Point value, JsonGenerator gen, SerializerProvider provider) throws IOException {
         gen.writeStartObject();
         gen.writeNumberField("lat", value.getY());
         gen.writeNumberField("lon", value.getX());
         gen.writeEndObject();
     }
    }
    
    0 讨论(0)
提交回复
热议问题