Jackson 在 Spring Boot 中反序列化 GeoJson Point
Posted
技术标签:
【中文标题】Jackson 在 Spring Boot 中反序列化 GeoJson Point【英文标题】:Jackson deserialize GeoJson Point in Spring Boot 【发布时间】:2018-01-24 14:51:11 【问题描述】:我有一个@Entity
模型,它的属性类型为com.vividsolutions.jts.geom.Point
。当我尝试在 @RestController
中渲染这个模型时,我得到一个递归异常。
(***Error); nested exception is
com.fasterxml.jackson.databind.JsonMappingException: Infinite
recursion (***Error) (through reference chain:
com.vividsolutions.jts.geom.Point[\"envelope\"]-
>com.vividsolutions.jts.geom.Point[\"envelope\"]....
实体看起来像这样(为了简洁而缩短):
@Entity
@Data
public class MyEntity
// ...
@Column(columnDefinition = "geometry")
private Point location;
// ...
经过一番研究,我发现这是因为 Jackson 默认无法反序列化 GeoJson。添加这个库应该可以解决问题:https://github.com/bedatadriven/jackson-datatype-jts。
我现在不确定如何在 Spring Boot 的对象映射器中包含这个模块。根据 boot 中的文档,我尝试通过以下两种方式将其添加到 @Configuration
:
@Bean
public Jackson2ObjectMapperBuilder jacksonBuilder()
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.modulesToInstall(new JtsModule());
return builder;
和
@Bean
public JtsModule jtsModule()
return new JtsModule();
两者都没有删除异常。抱歉,如果这是重复的,但我能找到的只是自定义 ObjectMapper
,据我了解,这不是“春季启动方式”。
作为一种解决方法,我是 @JsonIgnore
ing Point
并为不存在的协调对象提供自定义 getter 和 setter,...但这不是我想要保留它的方式。
【问题讨论】:
你想让Point location
不序列化吗?或者是其他东西 ?如果您有 @JsonIgnore 则对象未序列化。
不,我希望Point location
被序列化。 @JsonIgnore
只是自定义 getter 的临时解决方法,因此 Jackson 在序列化 Point
时不会死。
你找到解决办法了吗?
【参考方案1】:
请尝试进行如下更改,然后重试..
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
如下更改模型。
@Entity
@Data
public class MyEntity
// ...
@Column(columnDefinition = "geometry")
@JsonDeserialize(as = Point.class)
private Point location;
// ...
如果上述配置不适用于您的 JacksonSerializer 类,请尝试以下一次。
public class JacksonSerializer
private JacksonSerializer()
private static final ObjectMapper objectMapper = new ObjectMapper();
private static boolean isInit = false;
private static void init()
if (isInit == false)
objectMapper.setDefaultPropertyInclusion(Include.NON_EMPTY);
objectMapper.disable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
objectMapper.registerModule(new JavaTimeModule());
objectMapper.setDateFormat(new ISO8601DateFormat());
objectMapper.setAnnotationIntrospector(new JsonIgnoreIntrospector());
isInit = true;
【讨论】:
【参考方案2】:当我在 Spring Boot 中处理 Spring Boot 空间数据类型时,com.vividsolutions.jts.geom.Point 给我带来了很多问题。目前,我正在使用 Point of type
org.locationtech.jts.geom.Point
这就像一个魅力
【讨论】:
【参考方案3】:上述使用 JTSModule 的解决方法会导致我出现内部 SpringBoot 错误。我能够通过确保我的实体的 getter 方法返回字符串类型来解决这个问题。
@Entity
public class MyClassWithGeom
@Id
@GeneratedValue
private Long id;
private Point centre;
private Polygon boundary;
private MyClassWithGeom()
public MyClassWithGeom(String centreLat, String centreLng, Double[]... boundaryCoords)
String wkt = "POINT (" + centreLat + " " + centreLng + ")";
StringBuilder builder = new StringBuilder("POLYGON (( ");
for(int i=0;i<boundaryCoords.length;i++)
Double[] coord = boundaryCoords[i];
if (i < boundaryCoords.length - 1)
builder = builder.append(coord[0]).append(" ").append(coord[1]).append(", ");
else
builder = builder.append(coord[0]).append(" ").append(coord[1]).append(" ))");
try
this.centre = (Point) this.wktToGeometry(wkt);
logger.info(this.centre.toString());
this.boundary = (Polygon) this.wktToGeometry(builder.toString());
logger.info(this.boundary.toString());
catch (ParseException pe)
logger.error(pe.getMessage());
logger.error("Invalid WKT: " + wkt);
public Geometry wktToGeometry(String wellKnownText) throws ParseException
return new WKTReader().read(wellKnownText);
public String getCentre() return centre.toString();
public String getName() return name;
public String getBoundary() return boundary.toString();
【讨论】:
【参考方案4】:截至 2020 年,大多数 JTS 库都已过时,不再工作。我在 Maven Central 上发现了一个最近更新的分支,它与 jackson-core:2.10.0
和 jts-core:1.16.1
完美配合:
implementation 'org.n52.jackson:jackson-datatype-jts:1.2.4'
示例用法:
@Test
void testJson() throws IOException
var objectMapper = new ObjectMapper();
objectMapper.registerModule(new JtsModule());
GeometryFactory gf = new GeometryFactory();
Point point = gf.createPoint(new Coordinate(1.2345678, 2.3456789));
String geojson = objectMapper.writeValueAsString(point);
InputStream targetStream = new ByteArrayInputStream(geojson.getBytes());
Point point2 = objectMapper.readValue(targetStream, Point.class);
assertEquals(point, point2);
您不需要在类字段上使用任何注释或注册新的 Spring Bean,只需向 Jackson 注册 JTS 模块即可。
【讨论】:
如何向jackson注册jts模块? 我基本上必须使用 spring boot 来解决问题。我的服务返回一个实体列表,每个实体都有一个 locationtech.jts.geom.Geometry 字段。但是这个几何字段正在客户端引起递归响应。 @Mandroid 你找到解决方案了吗?可以分享一下吗? @ShehanSimen 您是否对递归或使 Spring Boot 与 JTS 一起工作有问题? @Ghostli 是的,真的很烦人。你有解决方案吗?我创建了自己的 POJO 类以在最后进行序列化,因为我找不到解决方案【参考方案5】:也许您应该使用@JsonSerialize
和@JsonDeserialize
标记您的几何属性。像这样:
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;
import fr.info.groloc.entity.json.GreffeDeserializer;
import javax.persistence.Entity;
@Entity
public class Table
@JsonSerialize(using = GeometrySerializer.class)
@JsonDeserialize(contentUsing = GeometryDeserializer.class)
private Geometry coord;
// ...
如果您使用的是 Spring-Boot,您只需要:
import com.bedatadriven.jackson.datatype.jts.JtsModule;
// ...
@Bean
public JtsModule jtsModule()
return new JtsModule();
正如 Dave 所说,您需要将此依赖项添加到您的 pom.xml:
<dependency>
<groupId>com.bedatadriven</groupId>
<artifactId>jackson-datatype-jts</artifactId>
<version>2.4</version>
</dependency>
【讨论】:
我自己也遇到了同样的问题,有两个小建议<dependency> <groupId>com.bedatadriven</groupId> <artifactId>jackson-datatype-jts</artifactId> <version>2.4</version> </dependency>
另外要与Spring boot一起使用,您需要包含import com.bedatadriven.jackson.datatype.jts.JtsModule;
谢谢@Kruschenstein!添加 JtsModule bean 即可解决问题。
@Kruschenstein - 我正在使用 Springboot。我应该把 Bean JtsModule 放在哪里?
@AlGrant 您可以将 bean 放在 Spring Framework 扫描的任何 @Configuration
注释类中。像 spring 管理的任何@Bean
一样!
这些步骤会导致 spring boot 回复错误 500。以上是关于Jackson 在 Spring Boot 中反序列化 GeoJson Point的主要内容,如果未能解决你的问题,请参考以下文章
在 Spring Boot + Spring Data Rest 中反序列化时忽略带有 @JsonProperty 的字段
无法在 Spring Boot 中反序列化嵌套对象“Role”
Spring Boot REST 服务:JSON 反序列化不起作用
无法从 START_OBJECT 令牌中反序列化 `java.lang.Long` 的实例;在 Spring Boot 帖子上