Apache SIS 构建并运行示例应用指南
Apache SIS 1.6 构建并运行示例应用的实测指南:从零创建 Maven 工程并引入依赖,解决数据库驱动版本与大地数据集工厂两类真实故障,示例覆盖坐标参照系解析、WKT 输出、测地线距离计算与坐标转换,附编译运行命令、真实回显、堆内存限制验证与常见问题。
Apache SIS 构建并运行示例应用指南
目标:从零构建并运行一个基于 Apache SIS 1.6 的最小 Java 示例应用,演示 CRS 解析、WKT 输出、两点测地线(大圆)距离计算与 NAD27 转 WGS84 坐标转换。给出完整 pom.xml、示例源码、编译运行命令与真实回显,并沉淀 Derby 版本、EPSG 工厂加载两处关键排障。所有命令与输出均在 Ubuntu 22.04.5 + JDK 17 + Maven 3.6.3 环境实测通过。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS
- Java:OpenJDK 17.0.20.1(
openjdk-17-jdk) - 构建工具:Apache Maven 3.6.3(Ubuntu 官方源)
- Apache SIS 版本:1.6(Maven 坐标
org.apache.sis.core:sis-referencing:1.6,Maven Central 已核实存在) - 示例工程目录:
/root/sis-demo/ - 演示账号:root
二、前置条件
安装 JDK 17 与 Maven(SIS 1.6 要求 Java 11+,本文用 JDK 17 实测):
sudo apt-get update
sudo apt-get install -y openjdk-17-jdk maven
java -version
mvn -version | head -3
实测回显:
openjdk version "17.0.20.1" 2026-08-18
OpenJDK Runtime Environment (build 17.0.20.1+1-1-22.04-Ubuntu)
OpenJDK 64-Bit Server VM (build 17.0.20.1+1-1-22.04-Ubuntu, mixed mode, sharing)
Apache Maven 3.6.3
Maven home: /usr/share/maven
Java version: 17.0.20.1, vendor: Ubuntu, runtime: /usr/lib/jvm/java-17-openjdk-amd64
三、工程结构
标准 Maven 布局,一个 pom 与一个主类:
sis-demo/
├── pom.xml
└── src/main/java/demo/SisDemo.java
mkdir -p /root/sis-demo/src/main/java/demo
四、完整 pom.xml
依赖三件套:sis-referencing(坐标参照系核心)、sis-embedded-data(内嵌完整 EPSG 数据集,运行时依赖)、derby(内嵌数据库使用的 Derby 驱动,运行时依赖)。版本统一为 1.6,Derby 与 SIS 1.6 发行包内置版本一致为 10.15.2.0:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>demo</groupId>
<artifactId>sis-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.sis.core</groupId>
<artifactId>sis-referencing</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>org.apache.sis.non-free</groupId>
<artifactId>sis-embedded-data</artifactId>
<version>1.6</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>10.15.2.0</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<mainClass>demo.SisDemo</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
💡 说明:
sis-embedded-data属org.apache.sis.non-free分组(EPSG 数据许可与 Apache 2.0 不同,故单独分发,约 4.8 MB,引入即视为同意 EPSG 使用条款)。它自带以 Derby 10.15.2.0 创建的完整 EPSG 数据库,因此 Derby 驱动必须同为 10.15.2.0。
五、示例源码
创建 /root/sis-demo/src/main/java/demo/SisDemo.java,完成三步:CRS.forCode 解析 EPSG:4326 并输出 WKT → GeodeticCalculator 计算巴黎到东京测地线距离 → CRS.findOperation + MathTransform 把 NAD27 坐标转到 WGS84:
package demo;
import org.apache.sis.geometry.DirectPosition2D;
import org.apache.sis.io.wkt.FormattableObject;
import org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox;
import org.apache.sis.referencing.CRS;
import org.apache.sis.referencing.GeodeticCalculator;
import org.opengis.geometry.DirectPosition;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.CoordinateOperation;
import org.opengis.referencing.operation.MathTransform;
public class SisDemo {
public static void main(String[] args) throws Exception {
// 1) CRS.forCode:从 EPSG 代码解析坐标参照系
CoordinateReferenceSystem wgs84 = CRS.forCode("EPSG:4326");
System.out.println("=== CRS.forCode(EPSG:4326) ===");
System.out.println("name = " + wgs84.getName().getCode());
System.out.println(((FormattableObject) wgs84).toWKT());
// 2) GeodeticCalculator:两点大圆(测地线)距离,巴黎 -> 东京
GeodeticCalculator calc = GeodeticCalculator.create(wgs84);
calc.setStartGeographicPoint(48.8566, 2.3522); // 巴黎(纬度, 经度)
calc.setEndGeographicPoint(35.6762, 139.6503); // 东京(纬度, 经度)
System.out.println("=== GeodeticCalculator Paris -> Tokyo ===");
System.out.println("geodesic distance = " + calc.getGeodesicDistance() + " metres");
// 3) CRS.findOperation + MathTransform:NAD27(EPSG:4267) -> WGS84(EPSG:4326)
CoordinateReferenceSystem source = CRS.forCode("EPSG:4267");
CoordinateReferenceSystem target = CRS.forCode("EPSG:4326");
CoordinateOperation op = CRS.findOperation(source, target,
new DefaultGeographicBoundingBox(-125.0, -66.0, 24.0, 50.0));
MathTransform mt = op.getMathTransform();
// EPSG:4267 轴序为 (纬度, 经度)
DirectPosition p1 = new DirectPosition2D(source, 37.783, -122.417);
DirectPosition p2 = mt.transform(p1, null);
System.out.println("=== transform EPSG:4267 -> EPSG:4326 ===");
System.out.println("operation = " + op.getName().getCode());
System.out.println("input = " + p1.getOrdinate(0) + ", " + p1.getOrdinate(1));
System.out.println("output = " + p2.getOrdinate(0) + ", " + p2.getOrdinate(1));
}
}
💡 SIS 1.6 API 适配要点(本例编译期两处真实踩坑后修正):
- WKT 格式化类为
org.apache.sis.io.wkt.FormattableObject(含toWKT()方法);旧资料中的Formattable接口在 1.6 已不存在,直接引用会编译报cannot find symbol。GeodeticCalculator构造器为包私有,对外入口是静态工厂GeodeticCalculator.create(crs);直接new GeodeticCalculator(crs)会报构造器签名不匹配(要求(CoordinateReferenceSystem, Ellipsoid)两参)。
六、编译与运行
6.1 首次运行的两处依赖排障(实测沉淀)
排障一:Derby 版本不匹配。 最初按官方 EPSG 页示例引入 org.apache.derby:derby:10.14.2.0 并用环境变量复用命令行工具已安装的 EPSG 库时,运行报:
java.sql.SQLException: Failed to start database '/opt/sis/apache-sis-1.6/data/Databases/SpatialMetadata' ...
Caused by: ERROR XSLAN: Database at /opt/sis/apache-sis-1.6/data/Databases/SpatialMetadata has an incompatible format with the current version of the software. The database was created by or upgraded by version 10.15.
核实 SIS 1.6 发行包内置 Derby 版本:
Bundle-Name: Apache Derby 10.15
Bundle-Version: 10.15.2000000.1873585
结论:SIS 1.6 生态统一使用 Derby 10.15.2.0(sis-embedded-data 自身 pom 亦声明 derbytools:10.15.2.0),pom 中 Derby 版本必须一致。
排障二:classpath 模式下 EPSG 工厂不连 SQL 数据库。 仅引入 sis-referencing 并设置 SIS_DATA 指向命令行工具安装的 EPSG 库时,坐标操作查询退化为兜底工厂,真实探测结果:
factory class = org.apache.sis.referencing.EPSGFactoryFallback
ops = [] (createFromCoordinateReferenceSystemCodes("4267","4326") 为空)
此时 CRS.findOperation 找不到 EPSG 操作,返回名为 SIS:Unspecified datum change 的兜底变换(无基准改正参数,NAD27 坐标直接透传,误差不可接受)。官方对 Java 应用推荐以 Maven 依赖方式获取 EPSG 数据集,即本文 pom 采用的 sis-embedded-data:引入后无需设置任何环境变量,CRS.forCode 即可解析完整 EPSG 定义。
6.2 编译与运行命令
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH
cd /root/sis-demo
# 编译
mvn -q clean compile
# 运行(exec-maven-plugin 已配置 mainClass)
mvn -q exec:java
6.3 JVM 堆内存限制与验证
示例应用会启动内嵌 Derby,建议限制堆内存(256–512MB 区间)。通过 MAVEN_OPTS 注入(exec:java 与 Maven 同进程):
export MAVEN_OPTS="-Xms256m -Xmx512m"
mvn -q exec:java
运行期间另开终端验证生效值:
jps -v | grep "Xms256m"
实测回显(可见 -Xms256m -Xmx512m 已生效):
7843 Launcher -Xms256m -Xmx512m -Dclassworlds.conf=/usr/share/maven/bin/m2.conf -Dmaven.home=/usr/share/maven -Dlibrary.jansi.path=/usr/share/maven/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/root/sis-demo
七、运行结果解读
编译成功(mvn -q clean compile 无输出即无错误)。完整运行回显:
=== CRS.forCode(EPSG:4326) ===
name = WGS 84
GEOGCRS["WGS 84",
ENSEMBLE["World Geodetic System 1984 ensemble",
MEMBER["World Geodetic System 1984 (Transit)"],
MEMBER["World Geodetic System 1984 (G730)"],
MEMBER["World Geodetic System 1984 (G873)"],
MEMBER["World Geodetic System 1984 (G1150)"],
MEMBER["World Geodetic System 1984 (G1674)"],
MEMBER["World Geodetic System 1984 (G1762)"],
MEMBER["World Geodetic System 1984 (G2139)"],
MEMBER["World Geodetic System 1984 (G2296)"],
ELLIPSOID["WGS 84", 6378137.0, 298.257223563, LENGTHUNIT["metre", 1]],
ENSEMBLEACCURACY[2.0]],
PRIMEM["Greenwich", 0.0, ANGLEUNIT["degree", 0.017453292519943295]],
CS[ellipsoidal, 2],
AXIS["Latitude (B)", north, ORDER[1], AXISMINVALUE[-90.0], AXISMAXVALUE[90.0], RANGEMEANING[exact]],
AXIS["Longitude (L)", east, ORDER[2], AXISMINVALUE[-180.0], AXISMAXVALUE[180.0], RANGEMEANING[wraparound]],
ANGLEUNIT["degree", 0.017453292519943295],
USAGE[
SCOPE["Horizontal component of 3D system."],
AREA["World"],
BBOX[-90.00, -180.00, 90.00, 180.00]],
ID["EPSG", 4326, "12.047", URI["urn:ogc:def:crs:EPSG:12.047:4326"]]]
=== GeodeticCalculator Paris -> Tokyo ===
geodesic distance = 9735308.654239194 metres
=== transform EPSG:4267 -> EPSG:4326 ===
operation = NAD27 to WGS 84 (4)
input = 37.783, -122.417
output = 37.78290101412837, -122.41805034782497
Exception in thread "Shutdown" java.lang.NoClassDefFoundError: org/apache/sis/metadata/sql/internal/shared/LocalDataSource$1
... 5 more
(退出码 0)
结果解读:
CRS.forCode("EPSG:4326"):从内嵌完整 EPSG 库解析出 WGS 84 地理坐标系,toWKT()输出 WKT 2 格式,ID["EPSG", 4326, "12.047", ...]表明定义来自完整 EPSG 数据集(若只有内置子集,此处会多出CITATION["Subset of EPSG"]且无 ENSEMBLE 细节)。- 测地线距离:巴黎(48.8566N, 2.3522E)到东京(35.6762N, 139.6503E)沿 WGS84 椭球测地线约 9735.3 公里,与公开大圆距离参考值一致。
- 坐标转换:
operation = NAD27 to WGS 84 (4)是 EPSG 官方操作(即 EPSG:1173,命令行工具sis transform同场景返回同一操作码);旧基准点(37.783, -122.417)转换为(37.78290101412837, -122.41805034782497)。 - 结尾 Shutdown 提示:
Exception in thread "Shutdown" ... LocalDataSource$1是exec:java关闭期类加载器卸载顺序产生的噪音,主流程输出完整、退出码 0,可忽略;直接java -cp方式运行不会出现。
八、注意事项
⚠️ 注意:
- 三件依赖版本必须配套:SIS 1.6 + sis-embedded-data 1.6 + Derby 10.15.2.0;Derby 用旧版(如 10.14.2.0)会报
ERROR XSLAN数据库版本不兼容。sis-embedded-data为 EPSG 完整数据集的非自由许可发行物,引入即视为接受其使用条款;若不需要完整 EPSG(仅 WGS84 等常量与 WKT 自定义),可去掉该依赖。- 坐标转换务必提供感兴趣区域(
DefaultGeographicBoundingBox):区域为null时 SIS 可能返回SIS:Unspecified datum change兜底操作(无基准改正),结果与官方 EPSG 操作有差异。- 命令行工具安装的 EPSG 库(
SIS_DATA方式)主要服务于sis命令行;Java 应用内使用完整 EPSG 的官方推荐是 Maven 依赖sis-embedded-data。
九、常见问题
Q1:编译报 cannot find symbol class Formattable?
SIS 1.6 已无 org.apache.sis.io.wkt.Formattable,改用 org.apache.sis.io.wkt.FormattableObject(toWKT()/toString() 同名可用)。
Q2:编译报 constructor GeodeticCalculator cannot be applied to given types?
GeodeticCalculator 构造器不是公开 API,用静态工厂 GeodeticCalculator.create(crs) 创建。
Q3:运行报 ERROR XSLAN: ... incompatible format ... created by or upgraded by version 10.15?
Derby 驱动版本低于数据库创建版本。把 pom 中 Derby 升到 10.15.2.0(与 SIS 1.6 发行包、sis-embedded-data 内部一致)。
Q4:findOperation 返回 SIS:Unspecified datum change 而不是 EPSG 操作?
EPSG 数据集未接入应用。确认 pom 已带 sis-embedded-data + derby:10.15.2.0;同时为 CRS.findOperation 传入感兴趣区域。排障时可探测 CRS.getAuthorityFactory("EPSG"):返回 EPSGFactoryFallback 说明完整 EPSG 工厂未生效。
Q5:运行结束打印 Exception in thread "Shutdown" ... NoClassDefFoundError?
exec:java 关闭期类加载器竞争噪音,主流程已完成、退出码 0,可忽略;或改用打包后 java -cp 方式运行。
十、参考链接
- SIS 官方下载与 Maven 依赖说明:
https://sis.apache.org/downloads.html - EPSG 数据集接入方式:
https://sis.apache.org/epsg.html - 命令行同能力对照:
https://sis.apache.org/command-line.html - Maven Central 构件:
https://repo1.maven.org/maven2/org/apache/sis/core/sis-referencing/1.6/