Search code examples
jacksonjts

Change the axis of lat long when using JTS jackson


I am using locationtech JTS library in spring boot with jackson as json serializer and a Jts-data-type module with supports serializing JTS geometry.The issue which i am facing is the axis order of coordinates when json is returned is long lat instead of lat long there is a solution on stackoverflow https://stackoverflow.com/a/29634389/1574921 i want to know if there is any other way to achieve this functionality instead of always applying InvertCoordinateFilter whenever i create a functionality. Below is the code which i am using

    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new JtsModule());


    double lat  = 32.3456789;
    double lng = 72.423434;

    GeometryFactory gf = new GeometryFactory();
    Point point = gf.createPoint(new Coordinate(lng,lat ));
    String json = mapper.writeValueAsString(point);
    System.out.println(json);

and the output is

{"type":"Point","coordinates":[72.423434,32.3456789]}

and i want output to be

{"type":"Point","coordinates":[32.3456789,72.423434]}

Solution

  • There is no way to tweak GeometrySerializer, since the order is hardcoded in lines 174-175.

    In order to avoid writing a serializer by yourself, you could just copy GeometrySerializer and invert those two lines, but you would effectively not be using the official jts-data-type, and future modifications on the library would not be reflected in your copied serializer unless you do it manually.

    Alternatively, just decorate the GeometrySerializer and use the InverseCoordinateFilter before calling it:

    public static class CustomGeometrySerializer extends JsonSerializer<Geometry> {
      private GeometrySerializer innerSerializer;
      private InvertCoordinateFilter inverter = new InvertCoordinateFilter();
    
      public CustomGeometrySerializer() {
        this(new GeometrySerializer());
      }
    
      public CustomGeometrySerializer(GeometrySerializer innerSerializer) {
        this.innerSerializer = innerSerializer;
      }
    
      @Override
      public void serialize(Geometry value, JsonGenerator jgen,
          SerializerProvider provider) throws IOException {
    
        // Create a new Geometry to avoid mutating the original one
        Geometry newValue = value.copy();
        newValue.apply(inverter);
        innerSerializer.serialize(newValue, jgen, provider);
      }
    
      private static class InvertCoordinateFilter implements CoordinateFilter {
        public void filter(Coordinate coord) {
          double oldX = coord.x;
          coord.x = coord.y;
          coord.y = oldX;
        }
      }
    }
    

    Now, instead of registering JtsModule, create a module yourself with your deserializer:

    ObjectMapper mapper = new ObjectMapper();
    
    SimpleModule inverseJtsModule = new SimpleModule();
    inverseJtsModule.addSerializer(Geometry.class, new CustomGeometrySerializer());
    mapper.registerModule(inverseJtsModule);
    
    double lat  = 32.3456789;
    double lng = 72.423434;
    
    GeometryFactory gf = new GeometryFactory();
    Point point = gf.createPoint(new Coordinate(lng, lat));
    String json = mapper.writeValueAsString(point);
    System.out.println(json);
    

    You can now safely serialize your geometries without explicitly inverting each one. For deserialization, you can use the same approach, decorating GeometryDeserializer.