Spring Boot 3.2如何自动注册Geolatte Jackson模块处理Point序列化反序列化
需求
在Spring Boot 3.2环境下,完成Geolatte JSON模块的自动注册,使用其自带的序列化/反序列化器,实现Geolatte Geometry Point<G2D>类型的JSON序列化与反序列化。
当前问题
手动在控制器中注册GeolatteGeomModule后接口可正常返回结果,但无法通过配置让Spring Boot自动加载该模块,导致接口调用时出现序列化失败的错误。
具体细节
- 实体类定义(初始带注解版本)
@Value @Data public class CheckDto implements Serializable { Long id; @JsonSerialize(using = GeometrySerializer.class) @JsonDeserialize(using = GeometryDeserializer.class) Point<G2D> location; // getters setters 等方法 }
- 尝试自动注册的配置类(未生效)
@Configuration @EnableEntityViews("com.nz.kiwi.model") @ComponentScan("com.nz.kiwi") public class AppConfig { @Bean public ObjectMapper mapper() { CoordinateReferenceSystem<G2D> crs = WGS84; ObjectMapper gMapper = new ObjectMapper(); gMapper.registerModule(new GeolatteGeomModule(crs)); return gMapper; } }
- 接口调用报错信息
Mon Sep 04 18:45:46 NZST 2023
There was an unexpected error (type=Internal Server Error, status=500).
No converter for [class com.nz.kiwi.view.HealthCheckDto] with preset Content-Type 'application/json'
org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class com.nz.kiwi.view.HealthCheckDto] with preset Content-Type 'application/json'
...(省略部分栈跟踪)
该错误说明Spring Boot并未识别到注册的GeolatteGeomModule,无法处理Point<G2D>类型的序列化。
- 手动注册可正常运行的场景
移除实体类上的序列化/反序列化注解:
@Value @Data public class CheckDto implements Serializable { Long id; //@JsonSerialize(using = GeometrySerializer.class) //@JsonDeserialize(using = GeometryDeserializer.class) Point<G2D> location; // getters setters 等方法 }
在控制器中手动创建并注册模块:
@Autowired private final ObjectMapper objectMapper; // 注册GeoLatteGeomModule public ObjectMapper mapper() { CoordinateReferenceSystem<G2D> crs = WGS84; ObjectMapper gMapper = new ObjectMapper(); gMapper.registerModule(new GeolatteGeomModule(crs)); gMapper.registerModule(new JavaTimeModule()); return gMapper; } // 获取带位置信息的测试数据 @GetMapping(value = "/custom5/{id}", produces = "application/json") public ResponseEntity<?> BirdSummaryDTOCustom5(@PathVariable Long id) throws JsonProcessingException { HealthCheckDto hcDto = customBirdRepository.customQuery5(id); ObjectMapper objectMapper = mapper(); String json = objectMapper.writeValueAsString(hcDto); return ResponseEntity.ok() .contentType(MediaType.APPLICATION_JSON) .header("Custom-Header", "birdApp") .body(json); }
此时接口可返回正确的JSON结果:
{ "id": 5, "catchDateTime": "2023-06-05 11:18", "releaseDateTime": "2023-06-05 11:45", "location": { "type": "Point", "crs": { "type": "name", "properties": { "name": "EPSG:4326" } }, "coordinates": [ 173.5, -35.5 ] } }
解决方案
问题出在原配置类中新建了一个ObjectMapper实例,但Spring Boot MVC使用的是由JacksonAutoConfiguration自动配置的全局ObjectMapper,因此手动创建的ObjectMapper并未被框架使用。正确的做法是通过Jackson2ObjectMapperBuilderCustomizer来定制全局的ObjectMapper,实现模块的自动注册:
正确的配置类
@Configuration @EnableEntityViews("com.nz.kiwi.model") @ComponentScan("com.nz.kiwi") public class AppConfig { @Bean public Jackson2ObjectMapperBuilderCustomizer geolatteModuleCustomizer() { CoordinateReferenceSystem<G2D> crs = WGS84; return builder -> builder.modules(new GeolatteGeomModule(crs), new JavaTimeModule()); } }
关键说明
- 使用
Jackson2ObjectMapperBuilderCustomizer可以直接对Spring Boot自动配置的ObjectMapper进行扩展,确保注册的模块被全局使用。 - 实体类可以完全移除
@JsonSerialize和@JsonDeserialize注解,因为GeolatteGeomModule会自动为Point<G2D>类型绑定对应的序列化/反序列化器。 - 同时注册
JavaTimeModule可以处理Java 8+的日期时间类型,避免额外的序列化问题。
配置完成后,无需在控制器中手动处理ObjectMapper,直接返回DTO对象即可实现自动序列化:
@GetMapping(value = "/custom5/{id}", produces = "application/json") public ResponseEntity<HealthCheckDto> BirdSummaryDTOCustom5(@PathVariable Long id) { HealthCheckDto hcDto = customBirdRepository.customQuery5(id); return ResponseEntity.ok() .contentType(MediaType.APPLICATION_JSON) .header("Custom-Header", "birdApp") .body(hcDto); }
内容的提问来源于stack exchange,提问作者Al Grant

