使用 RESTEasy / Jackson / Quarkus 将 JTS Geometry 解析为 GeoGSON

问题描述

我正在尝试将旧的 EJB 服务(内部逻辑)包装在微服务中。我使用 Quarkus / RESTEasy 来实现这个微服务

但是,我在自定义序列化/反序列化时遇到了问题。

问题:Cannot construct instance of com.vividsolutions.jts.geom.Geometry 这让我相信 Jackson 并没有将 Geometry 视为要解析为字符串的类。这导致相信我没有选择对象映射器..

注 1:我可以在 Quarkus 日志中提供的日志语句中看到:customizing ObjectMapper,adding geometry serializer / deserializer

注意 2:单元测试在 RegisterGeometryMapper 上运行良好。

这是我要解析的JSON(注意:几何是GeoGSON)

{
  "geometry": {
    "type": "Point","coordinates": [
      134750,477800,3.18
    ],"crs": {
      "type": "name","properties": {
        "name": "epsg:28992"
      }
    }
  },"date": 1612519294297
}

这是 REST 资源方法

    @POST
    @Path( "/etrs89-transformation" )
    @Consumes( MediaType.APPLICATION_JSON )
    @Produces( MediaType.APPLICATION_JSON )
    TransformationResult transformToEtrs89(@NotNull @Valid TransformationRequest request);

及其请求 DTO:

public class TransformationRequest {
    @NotNull private Geometry geometry;
    private Date date;
}

这是我注册的映射器。

@Singleton
public class RegisterGeometryMapper implements ObjectMapperCustomizer {

    private static final Logger LOG = Logger.getLogger( RegisterGeometryMapper .class );

    public void customize(ObjectMapper mapper) {
        LOG.debug( "customizing ObjectMapper,adding geometry serializer / deserializer." );
        SimpleModule module = new SimpleModule();
        module.addDeserializer( Geometry.class,new GeometryDeserializer() );
        module.addSerializer( Geometry.class,new GeometrySerializer() );
        mapper.registerModule( module );
    }

    public static class GeometryDeserializer extends StdDeserializer<Geometry> {

        private final GeoJsonReader reader = new GeoJsonReader();

        public GeometryDeserializer() {
            this( Geometry.class );
        }

        public GeometryDeserializer(Class<Geometry> vc) {
            super( vc );
        }

        @Override
        public Geometry deserialize(JsonParser jp,DeserializationContext ctxt) throws IOException,JsonProcessingException {
            JsonNode node = jp.getCodec().readTree( jp );
            String geoGson = node.toString();
            try {
                return reader.read( geoGson );
            }
            catch ( ParseException ex ) {
                throw new IOException( ex );
            }
        }
    }

    public static class GeometrySerializer extends StdSerializer<Geometry> {

        private final GeoJsonWriter writer = new GeoJsonWriter();

        protected GeometrySerializer() {
            this( Geometry.class );
        }

        protected GeometrySerializer(Class<Geometry> t) {
            super( t );
        }

        @Override
        public void serialize(Geometry geometry,JsonGenerator jgen,SerializerProvider serializerProvider) throws IOException {
            jgen.writerawValue( writer.write( geometry ) );
        }
    }
}

作者/读者源自 jts io。

        <!-- GeoJson -->
        <dependency>
            <groupId>com.vividsolutions</groupId>
            <artifactId>jts-io</artifactId>
            <version>1.14.0</version>
        </dependency>

此外:我坚持使用 jts(无法迁移到较新版本 - locationtech - 由于遗留原因,JBOSS EAP 停留在不支持 locationtech 的 Hibernate 上)。

解决方法

上述解决方案是正确且有效的。

问题是我在代码中的其他地方添加了:

@Provider
public class JacksonConfig implements ContextResolver<ObjectMapper> {
    private final ObjectMapper objectMapper;

    public JacksonConfig() throws Exception {
        objectMapper = new ObjectMapper();
        objectMapper.enable( SerializationFeature.WRITE_DATES_AS_TIMESTAMPS );
    }

    @Override
    public ObjectMapper getContext(Class<?> arg0) {
        return objectMapper;
    }
}

这会创建一个新的 ObjectMapper 并撤消我在 @Singleton 类中所做的一切。