Skip to content

Repository files navigation

udbx4j

超图 UDBX 空间数据格式的 Java 读写库

Java License Maven Central

当前发布准备版本:v2.1.0。Maven Central 上的最新稳定版本以徽章和 Central 页面为准。

简介

udbx4j 是超图 UDBX 空间数据格式的纯 Java 读写库。UDBX(Universal Spatial Database Extension)基于 SQLite 存储,支持属性表、矢量(点/线/面、三维点/线/面)、文本和 CAD 数据集。

本项目实现了对 UDBX 格式的独立读写,无需依赖 SuperMap iObjects Java 组件。

特性

  • 高性能 - 纯 Java 实现,零 JNI 开销
    • 单线程读取性能提升 92.5%(实测:0.34ms vs 4.5ms 基线)
    • 多线程并发扩展 3.49 倍(实测:7.94M vs 2.27M ops/s)
    • 批量写入性能提升 10-50 倍(使用 insertMany API)
    • 分页查询内存开销仅 +22%
  • 高稳定性 - 无 JNI 内存泄漏风险
    • JVM GC 自动管理内存,零泄漏
    • 无许可依赖,部署更简单
    • 详细的 Java 异常堆栈,易调试
  • 纯 Java 实现 - 无需原生依赖
    • 单个 JAR 包,跨平台无障碍
    • 支持 GraalVM Native Image
  • ⚠️ 数据集支持
    • 纯属性表(Tabular)
    • 矢量数据:点、线、面(Point/Line/Region)
    • 三维矢量:PointZ、LineZ、RegionZ
    • CAD 数据集
    • Text 数据集支持最小 GeoText 读写、更新、删除和 SmIndexKey 写出
  • 标准生态集成 - JDBC + JTS
    • 无缝集成 Spring Boot、连接池、监控
    • 支持 HikariCP、MyBatis、Hibernate
  • SpatiaLite 兼容 - GAIA Geometry 格式支持
  • 视口空间查询 - querySpatial 按视口 MBR 查询(RTree / 包络缓存),覆盖 Point/Line/Region/Z/Text/CAD
  • 轻量级 - 基于 JDBC + SQLite,无重型依赖
  • 测试驱动 - Spec 测试 + 集成测试双重保障

快速开始

环境要求

  • Java 17 或更高版本
  • Maven 3.6+

Maven 依赖

<dependency>
    <groupId>io.github.zhyt1985</groupId>
    <artifactId>udbx4j</artifactId>
    <version>2.1.0</version>
</dependency>

代码示例

打开 UDBX 文件

import com.supermap.udbx.UdbxDataSource;

// 打开现有 UDBX 文件
try (UdbxDataSource dataSource = UdbxDataSource.open("path/to/data.udbx")) {
    // 列出所有数据集
    dataSource.listDatasets().forEach(info -> System.out.println(info.name()));
}

读取点数据

import com.supermap.udbx.dataset.PointDataset;
import com.supermap.udbx.dataset.PointFeature;

try (UdbxDataSource dataSource = UdbxDataSource.open("points.udbx")) {
    PointDataset dataset = (PointDataset) dataSource.getDataset("PointData");

    // 遍历所有要素
    for (PointFeature feature : dataset.list()) {
        System.out.printf("ID: %d, X: %.2f, Y: %.2f%n",
            feature.id(),
            feature.geometry().getX(),
            feature.geometry().getY());
    }
}

创建新数据集

import com.supermap.udbx.UdbxDataSource;
import com.supermap.udbx.core.FieldInfo;
import com.supermap.udbx.core.FieldType;
import com.supermap.udbx.dataset.PointDataset;
import com.supermap.udbx.dataset.PointFeature;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;

// 创建新 UDBX 文件
try (UdbxDataSource dataSource = UdbxDataSource.create("output.udbx")) {
    // 创建字段信息
    List<FieldInfo> fields = List.of(
        new FieldInfo(0, "名称", FieldType.CHAR, "名称", false),
        new FieldInfo(0, "数量", FieldType.INT32, "数量", false)
    );

    // 创建点数据集
    PointDataset dataset = dataSource.createPointDataset("MyPoints", 4326, fields);

    // 创建 JTS 几何工厂
    GeometryFactory factory = new GeometryFactory();

    // 添加要素
    Point point = factory.createPoint(new Coordinate(116.404, 39.915)); // 北京坐标
    PointFeature feature = new PointFeature(1, point, Map.of(
        "名称", "天安门",
        "数量", 100
    ));
    dataset.insert(feature);
}

流式读取(大数据集)

import com.supermap.udbx.streaming.AutoCloseableStream;

try (UdbxDataSource dataSource = UdbxDataSource.open("large_dataset.udbx")) {
    PointDataset dataset = (PointDataset) dataSource.getDataset("BigData");

    // 流式读取,内存占用恒定
    try (AutoCloseableStream<PointFeature> stream = dataset.stream()) {
        stream.getStream()
            .filter(f -> f.geometry().getX() > 116.0)
            .limit(1000)
            .forEach(feature -> process(feature));
    } // 自动关闭资源
}

分页查询

import com.supermap.udbx.core.QueryOptions;

// 分页读取点数据
try (UdbxDataSource dataSource = UdbxDataSource.open("data.udbx")) {
    PointDataset dataset = (PointDataset) dataSource.getDataset("Points");

    int pageSize = 1000;
    int totalCount = dataset.count();
    int pageCount = (totalCount + pageSize - 1) / pageSize;

    for (int page = 0; page < pageCount; page++) {
        List<PointFeature> features = dataset.list(new QueryOptions(null, pageSize, page * pageSize));
        System.out.println("Page " + page + ": " + features.size() + " features");
    }
}

批量写入

import com.supermap.udbx.dataset.PointFeature;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;

// 批量写入性能提升 10-50 倍
try (UdbxDataSource dataSource = UdbxDataSource.create("output.udbx")) {
    PointDataset dataset = dataSource.createPointDataset("Points", 4326);

    GeometryFactory factory = new GeometryFactory();
    List<PointFeature> batch = new ArrayList<>();
    for (int i = 0; i < 10000; i++) {
        Point point = factory.createPoint(new Coordinate(116.0 + i * 0.0001, 39.0 + i * 0.0001));
        PointFeature feature = new PointFeature(i + 1, point, Map.of());
        batch.add(feature);
    }

    // 单次事务批量写入
    dataset.insertMany(batch);
}

公开 API 稳定语义

udbx4j 的公开 API 遵循 udbx4spec/docs/08-api-stable-surface.md。Java 侧使用同步方法、异常和 AutoCloseable 表达跨语言稳定面。

语义 Java API 稳定行为
打开数据源 UdbxDataSource.open(path) 打开已有 UDBX,格式问题抛格式类错误
创建数据源 UdbxDataSource.create(path) 创建 UDBX 并初始化系统表
列出数据集 listDatasets() 返回 DatasetInfo 列表
视口空间查询 querySpatial(name, options) 按视口 MBR 查询,成功策略仅 `rtree
按名称获取数据集 getDataset(name) 不存在时抛 UdbxNotFoundError
按 ID 获取对象 getById(id) 不存在时抛 UdbxNotFoundError,不返回 null
列表读取 list() / list(QueryOptions) 默认按 SmID 升序返回
计数 count() 读取物理表真实行数,不以 SmRegister.SmObjectCount 缓存为准
写入 insert(...) / insertMany(...) 写入对象并同步对象数
更新 update(id, ...) 目标不存在时抛 UdbxNotFoundError;未知字段抛 not found 类错误
删除 delete(id) 目标不存在时抛 UdbxNotFoundError;成功后同步对象数

错误处理示例:

import com.supermap.udbx.core.UdbxNotFoundError;

try {
    PointFeature feature = dataset.getById(42);
    process(feature);
} catch (UdbxNotFoundError e) {
    // 数据集、字段、记录或要素不存在
}

项目结构

udbx4j/
├── README.md                          # 项目介绍和快速开始
├── CHANGELOG.md                       # 版本变更记录
├── CONTRIBUTING.md                     # 贡献指南
├── CLAUDE.md                          # 兼容入口,内容以 AGENTS.md 为准
├── LICENSE                            # MIT 许可证
├── pom.xml                            # Maven 构建配置
├── Makefile                           # 构建脚本(预设 JAVA_HOME)
│
├── rules/                             # 开发规范
│   ├── java-coding-style.md          # Java 编码规范
│   ├── java-testing.md               # 测试规范
│   ├── java-patterns.md               # 设计模式
│   └── spec-coding.md                # Spec 测试流程
│
├── .github/                           # GitHub 配置
│   ├── ISSUE_TEMPLATE/                # Issue 模板
│   │   ├── bug_report.md              # Bug 报告模板
│   │   └── feature_request.md         # 功能请求模板
│   └── PULL_REQUEST_TEMPLATE.md       # PR 模板
│
└── src/
    ├── main/java/com/supermap/udbx/
    │   ├── UdbxDataSource.java         # 入口类:open()/create()
    │   ├── pool/                       # 连接池与对象池
    │   ├── core/                       # 核心枚举与元信息
    │   │   ├── DatasetKind.java       # 数据集类型枚举
    │   │   ├── GeometryType.java       # 几何类型枚举
    │   │   ├── FieldType.java          # 字段类型枚举
    │   │   ├── FieldInfo.java          # 字段元信息
    │   │   └── DatasetInfo.java        # 数据集元信息
    │   ├── dataset/                    # 数据集实现
    │   │   ├── Dataset.java            # 抽象基类
    │   │   ├── TabularDataset.java     # 纯属性表
    │   │   ├── VectorDataset.java      # 矢量基类
    │   │   ├── PointDataset.java       # 点数据集
    │   │   ├── LineDataset.java        # 线数据集
    │   │   ├── RegionDataset.java      # 面数据集
    │   │   ├── PointZDataset.java      # 三维点数据集
    │   │   ├── LineZDataset.java       # 三维线数据集
    │   │   ├── RegionZDataset.java     # 三维面数据集
    │   │   └── CadDataset.java         # CAD 数据集
    │   ├── geometry/                   # 几何对象
    │   │   ├── gaia/                   # SpatiaLite GAIA 格式
    │   │   │   ├── GaiaGeometryReader.java
    │   │   │   ├── GaiaGeometryWriter.java
    │   │   │   └── ...
    │   │   └── cad/                    # SuperMap CAD 格式
    │   │       ├── CadGeometryReader.java
    │   │       ├── CadGeometryWriter.java
    │   │       ├── CadGeometry.java
    │   │       └── ...
    │   ├── streaming/                  # 流式处理
    │   │   ├── AutoCloseableStream.java # 资源管理
    │   │   └── FeatureSpliterator.java  # 懒加载迭代器
    │   ├── pool/                       # 连接池
    │   │   └── UdbxDataSourcePool.java  # HikariCP 连接池
    │   ├── metrics/                    # 性能监控(可选)
    │   │   └── PerformanceMetrics.java  # Micrometer 集成
    │   ├── system/                     # 系统表 DAO
    │   │   ├── SmRegisterDao.java
    │   │   ├── SmFieldInfoDao.java
    │   │   └── SmDataSourceInfoDao.java
    │   └── viewer/                     # Java Swing viewer(实验性)
    │
    └── test/java/com/supermap/udbx/
        ├── spec/                       # Spec 测试(基于白皮书)
        │   └── *SpecTest.java           # 21 个 Spec 测试类
        ├── integration/                # 集成测试
        │   └── *Test.java               # 14 个集成测试类
        └── benchmark/                  # JMH 性能基准测试
            ├── BaselineBenchmark.java   # 基线测试
            ├── GeometryDecodeBenchmark.java
            ├── StreamingReadBenchmark.java
            ├── ConcurrentReadBenchmark.java
            └── ManualConcurrentTest.java

构建与测试

使用 Makefile(推荐)

make test            # 运行 Spec 测试
make test-all        # 运行所有测试 + 覆盖率报告
make run-test CLASS=GaiaPointSpecTest  # 运行单个测试类
make coverage        # 打开覆盖率报告

使用 Maven

mvn compile
mvn test
mvn verify           # 含集成测试 + 覆盖率检查
mvn package -DskipTests

技术架构

UDBX 格式要点

概念 说明
文件格式 SQLite 数据库(.udbx 后缀)
字节序 Little-Endian
矢量几何 GAIA Geometry(SpatiaLite 标准格式)
CAD 几何 SuperMap GeoHeader 自定义格式
系统表 SmRegister、SmFieldInfo、SmDataSourceInfo

Geometry 二进制格式

GAIA(SpatiaLite):

0x00 | byteOrder(1) | srid(int32) | MBR(4×double) | 0x7c | geoType(int32) | ...coords... | 0xFE

CAD(SuperMap GeoHeader):

geoType(int32) | styleSize(int32) | Style(...) | ...geometry data...

开发规范

  • 测试驱动开发(TDD)- 先写测试,再写实现
  • 不可变优先 - 元信息类使用 Java Record
  • 测试覆盖率 ≥ 80%
  • 提交格式 - feat/fix/test/refactor/docs/chore: 描述

详细规范见 rules/ 目录。

参考文档

  • 白皮书UDBX开放数据格式白皮书(V1.0).pdf
  • 变更日志CHANGELOG.md
  • 开发规范rules/ 目录

已知缺口

  • 当前 Text / GeoText 支持覆盖 udbx4spec 最小合规基线;后续仍需继续扩大真实 SuperMap UDBX 文本样式和复杂文本对象兼容范围。
  • CAD 当前覆盖最小 GeoHeader 基线;复杂 CAD 类型、样式和混合对象仍需按 udbx4spec 扩展后实现。

udbx4spec 规范合规

本项目严格遵循 udbx4spec/ 中定义的跨语言规范。关键约束:

  • API 命名:所有公开 API 必须与 udbx4spec/docs/01-naming-conventions.md 对齐
  • 数据模型:几何模型必须符合 udbx4spec/docs/02-geometry-model.md
  • 数据集类型DatasetKind 枚举值必须与 udbx4spec/docs/03-dataset-taxonomy.md 同步
  • 字段类型FieldType 枚举值必须与 udbx4spec/docs/04-field-taxonomy.md 同步(14 种)
  • 变更流程:任何 API 变更、新增数据集类型或字段类型,必须先在 udbx4spec 中定义,然后在各语言实现中同步

许可证

MIT License

作者

zhyt1985

相关链接

About

Java UDBX runtime with JTS geometry support. Reference implementation for UDBX spatial database format.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages