在Sping Boot 3.2中注册GeolatteJackson模块

xbp102n0  于 7个月前  发布在  其他
关注(0)|答案(2)|浏览(63)

希望能够在Sping Boot 3.2中通过成功注册Geolatte JSON模块并使用其验证器来验证Geolatte Geometry
我可以在控制器中手动注册GeolatteGeomModule,但不能让Sping Boot 自动拿起它。

实体

带有点数据的我的实体是:

@Value
@Data
public class CheckDto implements Serializable {

    Long id;
    @JsonSerialize(using = GeometrySerializer.class)
    @JsonDeserialize(using = GeometryDeserializer.class)
    Point<G2D> location;
    // getters setters etc
}

然后我的AppConfig自动注册Jackson的自定义GeolatterGeomModule

AppConfig

@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'
    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:319)
    at org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:245)
    at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:78)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:136)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1081)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:974)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903)
    at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
    at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:166)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:894)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1740)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:833)

从上面看,GeolatteGeomModule没有被拾取。
如果我修改我的控制器以手动调用GeolatteGeomModule并从实体中删除@JsonDeserialize(using = GeometryDeserializer.class),那么我有:

实体

@Value
@Data
public class CheckDto implements Serializable {

    Long id;
    //@JsonSerialize(using = GeometrySerializer.class)
    //@JsonDeserialize(using = GeometryDeserializer.class)
    Point<G2D> location;
    // getters setters etc
}

我的控制器:

控制器

@Autowired
private final ObjectMapper objectMapper;

// register the GeoLatteGeomModule
public ObjectMapper mapper() {
    CoordinateReferenceSystem<G2D> crs = WGS84;
    ObjectMapper gMapper = new ObjectMapper();
    gMapper.registerModule(new GeolatteGeomModule(crs));
    gMapper.registerModule(new JavaTimeModule());
    return gMapper;
}

// Get test data with location
@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);
}

我得到了预期的结果:

{
        "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
        ]
    }
}

我如何让spring注册模块,使其自动完成?

fcg9iug3

fcg9iug31#

与创建自己的Object Mapper不同,定制Sping Boot 为webapps自动创建的Object Mapper更容易。
有多种方法可以做到这一点,如下所述:https://www.baeldung.com/spring-boot-customize-jackson-objectmapper
在你的情况下,这应该是足够的:

@Bean
public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
    CoordinateReferenceSystem<G2D> crs = WGS84;
    return builder -> builder
            .serializationInclusion(JsonInclude.Include.NON_NULL)
            .modules(new GeolatteGeomModule(crs),
                    new JavaTimeModule());
}

使用此定制器和以下示例控制器和DTO:

@RestController
class GeolatteTestController {
    @GetMapping(value = "/custom5/{id}", produces = "application/json")
    public ResponseEntity<?> BirdSummaryDTOCustom5(@PathVariable Long id) {
        return ResponseEntity.ok()
                .contentType(MediaType.APPLICATION_JSON)
                .header("Custom-Header", "birdApp")
                .body(new CheckDto(id, point(WGS84, g(4.33, 53.21))));
    }
}

@Data
@AllArgsConstructor
class CheckDto implements Serializable {
    Long id;

    Point<G2D> location;
    // getters setters etc
}

点击localhost:8080/custom5/123将产生以下结果:

{
  "id": 123,
  "location": {
    "type": "Point",
    "crs": {
      "type": "name",
      "properties": {
        "name": "EPSG:4326"
      }
    },
    "coordinates": [
      4.33,
      53.21
    ]
  }
}

使用Sping Boot 3.2.0-M2和org.geolatte:geolatte-geojson:1.9.1进行测试。

hgtggwj0

hgtggwj02#

在您的示例中,您根本没有使用Auto-wire。
在你的第一个代码中,最好修改函数名:

@Bean
@Primary
public ObjectMapper myCustomMapper() {
    CoordinateReferenceSystem<G2D> crs = WGS84;
    ObjectMapper gMapper = new ObjectMapper();
    gMapper.registerModule(new GeolatteGeomModule(crs));
    return gMapper;
}

每当你需要它自动布线它像这样:

@Autowired
ObjectMapper myCustomMapper;

在控制器中删除此:

// register the GeoLatteGeomModule
public ObjectMapper mapper() {
    CoordinateReferenceSystem<G2D> crs = WGS84;
    ObjectMapper gMapper = new ObjectMapper();
    gMapper.registerModule(new GeolatteGeomModule(crs));
    gMapper.registerModule(new JavaTimeModule());
    return gMapper;
}

还有这个

ObjectMapper objectMapper = mapper();

像这样自动连接

@Autowired
ObjectMapper myCustomMapper;

相关问题