简体   繁体   English

使用 JTS 解析 WKB 几何的不一致异常

[英]Inconsistent Exception parsing WKB geometry using JTS

I am getting the strangest problem that I just can't wrap my head around.我遇到了最奇怪的问题,我无法解决这个问题。 My web api which uses Spring Boot and postgresql/postgis, is getting inconsistent errors when trying to read geometries from the database.我的 web api 使用 Spring Boot 和 postgresql/postgis,在尝试从数据库读取几何图形时出现不一致的错误。 I have been using this code (with occasional modifications of course) for many, many years and this just starting happening on my last release.我一直在使用这段代码(当然偶尔会修改)很多年了,这在我的上一个版本中才开始发生。

I am using openjdk 11.0.4 2019-07-16 on ubuntu 18.04.我在 ubuntu 18.04 上使用 openjdk 11.0.4 2019-07-16。 Relevent pom.xml entries ...相关的 pom.xml 条目...

        <groupId>org.locationtech.jts</groupId>
            <artifactId>jts-core</artifactId>
            <version>1.16.1</version>
        </dependency>

I am getting various errors from api calls of the following types ...我从以下类型的 api 调用中收到各种错误......

eg hexstring: 0101000020E6100000795C548B88184FC0206118B0E42750C0例如十六进制字符串:0101000020E6100000795C548B88184FC0206118B0E42750C0

org.locationtech.jts.io.ParseException: Unknown WKB type 0
    at org.locationtech.jts.io.WKBReader.readGeometry(WKBReader.java:235)
    at org.locationtech.jts.io.WKBReader.read(WKBReader.java:156)
    at org.locationtech.jts.io.WKBReader.read(WKBReader.java:137)
    at net.crowmagnumb.database.RecordSet.getGeom(RecordSet.java:1073)

eg hexstring: 0101000020E61000000080FB3F354F5AC0F3D30EF2C0773540例如十六进制字符串:0101000020E61000000080FB3F354F5AC0F3D30EF2C0773540

java.lang.ArrayIndexOutOfBoundsException: arraycopy: length -1 is negative
    at java.base/java.lang.System.arraycopy(Native Method)
    at org.locationtech.jts.io.ByteArrayInStream.read(ByteArrayInStream.java:59)
    at org.locationtech.jts.io.ByteOrderDataInStream.readDouble(ByteOrderDataInStream.java:83)
    at org.locationtech.jts.io.WKBReader.readCoordinate(WKBReader.java:378)
    at org.locationtech.jts.io.WKBReader.readCoordinateSequence(WKBReader.java:345)
    at org.locationtech.jts.io.WKBReader.readPoint(WKBReader.java:256)
    at org.locationtech.jts.io.WKBReader.readGeometry(WKBReader.java:214)
    at org.locationtech.jts.io.WKBReader.read(WKBReader.java:156)
    at org.locationtech.jts.io.WKBReader.read(WKBReader.java:137)
    at net.crowmagnumb.database.RecordSet.getGeom(RecordSet.java:1073)

eg hexstring: 0101000020E610000066666666669663C00D96D7371DD63440例如十六进制字符串:0101000020E610000066666666669663C00D96D7371DD63440

org.locationtech.jts.io.ParseException: Unknown WKB type 326
    at org.locationtech.jts.io.WKBReader.readGeometry(WKBReader.java:235)
    at org.locationtech.jts.io.WKBReader.read(WKBReader.java:156)
    at org.locationtech.jts.io.WKBReader.read(WKBReader.java:137)
    at net.crowmagnumb.database.RecordSet.getGeom(RecordSet.java:1073)

The relevant parts of my RecordSet code is below (so line numbers will not match above stack traces).我的 RecordSet 代码的相关部分如下(因此行号与堆栈跟踪上方的行号不匹配)。

public class RecordSet {
    private static final Logger logger = LoggerFactory.getLogger(RecordSet.class);
    private static WKBReader wkbReader;

    private static WKBReader getWKBReader() {
        if (wkbReader == null) {
            wkbReader = new WKBReader();
        }
        return wkbReader;
    }

    private static byte[] hexStringToByteArray(final String hex) {
        if (StringUtils.isBlank(hex)) {
            return null;
        }

        int len = hex.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16));
        }
        return data;
    }

    public static Geometry getGeom(final String geomStr) {
        byte[] byteArray = hexStringToByteArray(geomStr);
        if (byteArray == null) {
            return null;
        }
        try {
            return getWKBReader().read(byteArray);
        } catch (Throwable ex) {
            logger.error(String.format("Error parsing geometry [%s]", geomStr), ex);
            return null;
        }
    }
}

So the extreme weirdness is that所以极端奇怪的是

  1. It doesn't happen consistently.它不会一直发生。 The exact same api call when I try to repeat it works fine.当我尝试重复它时,完全相同的 api 调用工作正常。
  2. The reported hex strings in the exception message are perfectly correct!异常消息中报告的十六进制字符串完全正确! If I run them in a test program using the same code give the correct answer and no exception.如果我使用相同的代码在测试程序中运行它们,则给出正确的答案,没有例外。

Again all of the above reported hexstrings that lead to errors in production api calls are valid representations of POINT geometries.同样,上述所有导致生产 api 调用错误的十六进制字符串都是 POINT 几何图形的有效表示。

Is this some weird potential memory leak issue?这是一些奇怪的潜在内存泄漏问题吗?

Maybe this should have been obvious but in my defense I have been using the above code for many, many years (as I said) without issue so I think I just overlooked the obvious?也许这应该是显而易见的,但在我的辩护中,我已经使用上面的代码很多很多年了(正如我所说)没有问题,所以我想我只是忽略了显而易见的? Anyway, it suddenly dawned on me should I be reusing the same WKBReader over and over again in a multiple-threaded environment?无论如何,我突然意识到我应该在多线程环境中一遍又一遍地重用同一个 WKBReader 吗? Well, turns out no!好吧,事实证明没有!

If I just create a new WBBReader() with each call (instead of getting a single static WKBReader) it works fine.如果我只是在每次调用时创建一个新的 WBBReader()(而不是获取单个静态 WKBReader),它就可以正常工作。 Well there is the source of my "memory leak".那么这就是我的“内存泄漏”的来源。 Self caused!自己造成的!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM