Error de-serializing Geometry with Jackson

2020-07-27 04:58发布

问题:

I am trying to implement a simple geometry (GIS) controller with PostGIS database in Spring-Boot 2.2.1.

When I try to de-serialize my task entity which contains the Point Geometry I am getting error:

There was an unexpected error (type=Internal Server Error, status=500).
Could not write JSON: org.locationtech.jts.geom.Point cannot be cast to com.vividsolutions.jts.geom.Geometry; nested exception is com.fasterxml.jackson.databind.JsonMappingException: org.locationtech.jts.geom.Point cannot be cast to com.vividsolutions.jts.geom.Geometry `enter code here`(through reference chain: java.util.ArrayList[0]->com.example.depdev.entity.Task["location"])

My task entity is :

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
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 org.locationtech.jts.geom.Point;

@Entity
@Table(name = "task")
public class Task {

public Task () {
};

@Id
private Long id;
private String title;
@Column(columnDefinition = "geometry(Point,4326)")
@JsonSerialize(using = GeometrySerializer.class)
@JsonDeserialize(using = GeometryDeserializer.class)
private Point location;

// trimmed

I have tried to define location as both a point and a geometry but the error is the same.

My controller is able to persist a new task, but I get the previously posted error when I try to de-serialize it:

@GetMapping("/alltasks")
@ResponseBody
public List allTasks() throws JsonProcessingException {

    GeometryFactory gf = new GeometryFactory();
    Double y = -36.829;
    Double x = 174.896;

    Task testTask = new Task();
    testTask.setId(new Long(01));
    testTask.setTitle("Test Task");
    Point p = gf.createPoint(new Coordinate(x, y));
    p.setSRID(4326);
    testTask.setLocation(p);
    taskRepository.save(testTask);

    List<Task> listTasks = new ArrayList<>();
    listTasks = taskService.findAll();
    return listTasks;

I did have the recursion error that is posted here - but adding the JacksonConfig class has fixed this error.

For the sake of completeness here is the Jackson config class:

import com.bedatadriven.jackson.datatype.jts.JtsModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JacksonConfig {
    @Bean
    public JtsModule jtsModule() {
        return new JtsModule();
    }
}

My dependencies in my build.gradle is:

dependencies {
implementation 'org.hibernate:hibernate-spatial'
compile group: 'org.locationtech.jts', name: 'jts-core', version: '1.16.0'
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.10.0'
compile group: 'com.bedatadriven', name: 'jackson-datatype-jts', version: '2.4'
implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-data-ldap'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'org.postgresql:postgresql'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
    exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation 'org.springframework.security:spring-security-test'

What do I need to do to get the task entity to JSON without this error?

UPDATE

There is no reference in my code to vividsolutions:

回答1:

As other pointed out there is a dependency still using the old version of point geometry (vividsolutions.geom rather than the newer locationtech).

Fortunately someone has branched jackson-databind. This branch will work with location tech :

https://mvnrepository.com/artifact/com.graphhopper.external/jackson-datatype-jts/0.10-2.5-1



回答2:

The 3-rd party library which contains custom JTS Jackson serializers is still transitively using the old version.

As the vividsolutions namespace was translated to locationtech you get the runtime exception.

Consider to create a custom serializer which accepted the new locationtech geometries.



回答3:

In 2020 for me this was the only solution for Hibernate 2.4 + locationtech + spring boot 2.2.6. Go back hibernate version like this post Spring data JPA and Geometry type