CentOS 8 安装 Apache Commons JXPath 指南
在 CentOS 8 上从零引入 Apache Commons JXPath 1.4.0:JDK 8 与 17 并存下的 JAVA_HOME 配置、Maven 在线依赖与官方二进制包两种安装方案及 UnsupportedClassVersionError 排障,全部命令附真实回显。
CentOS 8 安装 Apache Commons JXPath 指南
目标:在 CentOS 8 上从零搭建 Apache Commons JXPath 1.4.0 的使用环境,完成多 JDK 并存下的 JAVA_HOME 配置、在线 Maven 依赖与官方二进制包两种获取方式,并用真实的 Bean 对象图导航程序验证安装结果。以下全部命令与回显均已在 CentOS 8(x86_64)实测通过。
一、环境信息
本节先固定本次实测所用软硬件基线,便于读者逐项对照复现。CentOS 8 环境的显著特点是系统默认 Java 为 1.8、另装有 JDK 17,本文全部构建与运行步骤都围绕这一点展开。
- 操作系统:CentOS Linux 8(x86_64)
- 系统默认 JDK:OpenJDK 1.8.0_312(
java -version实测,回显见 4.2) - 另装 JDK:OpenJDK 17.0.1(位于
/usr/lib/jvm/java-17-openjdk,回显见 4.2) - 构建工具:Apache Maven 3.5.4(Red Hat 构建版,
mvn -v实测,回显见 4.2) - 目标库:Apache Commons JXPath 1.4.0(Maven 坐标
commons-jxpath:commons-jxpath:1.4.0,注意是旧 groupId,见第三章) - 依赖来源:
https://repo.maven.apache.org/maven2/(Maven 中央仓库)、https://downloads.apache.org/commons/jxpath/(官方发行目录),网络直连可达 - Maven 示例工程目录:
/opt/jxpath-demo - 官方二进制包解压目录:
/opt/jxpath-dist - 二进制包演示目录:
/opt/jxpath-dist-demo
Commons JXPath 是 Apache 基金会的对象图导航库(对象图导航指用 XPath 表达式访问 JavaBean 属性、集合与 XML 文档,选型对比见第三章技术拓展)。它以 jar 形式嵌入应用,无独立守护进程、无端口,安装本质上是「让应用能拿到这一个 jar」。
二、前置条件
在开始安装前,请确认以下条件满足,否则后续步骤会因权限或网络问题中断。
- root 权限或 sudo:需要在
/opt下创建目录并写入文件。 - 网络可达:需要访问
repo.maven.apache.org(Maven 中央仓库)与downloads.apache.org(官方二进制包)。先做一次连通性预检,两个地址各探测一次(该命令同时验证了旧 groupId 坐标的 POM 确实存在于中央仓库):
curl -s -o /dev/null -w "%{http_code}\n" --connect-timeout 10 https://repo.maven.apache.org/maven2/commons-jxpath/commons-jxpath/1.4.0/commons-jxpath-1.4.0.pom
curl -s -o /dev/null -w "%{http_code}\n" --connect-timeout 10 https://downloads.apache.org/commons/jxpath/binaries/commons-jxpath-1.4.0-bin.tar.gz
输出:
200
200
两个 200 分别确认:中央仓库上 commons-jxpath:commons-jxpath:1.4.0 的 POM 可达(方案 A 可用)、官方二进制包可达(方案 B 可用)。
- 磁盘空间:官方二进制包实测 3,374,636 字节(约 3.4 MB),加上 Maven 本地仓库缓存建议预留 ≥ 200 MB。
- JDK 17 与 Maven 已就绪(重点):CentOS 8 常见 JDK 8 与 JDK 17 并存,系统 Maven 默认可能解析到 JDK 8,需按 4.3 节设置
JAVA_HOME;运行程序时java命令也可能解析到 1.8,需用 JDK 17 完整路径(4.6 节实测踩坑)。若系统未装,先执行dnf install -y java-17-openjdk-devel maven安装。
⚠️ 注意:若内网无法直连上述域名,需按企业代理配置放行,否则 Maven 依赖与官方包均无法获取。本文实测环境为直连。
三、版本选型说明
安装前先确认应选用的版本与坐标,JXPath 有两个与 Commons 家族其他组件不同的关键点:版本线断代、groupId 沿用旧名。本节逐项说明并给出选型结论。
3.1 版本线:1.3(2008)与 1.4.0 两代
JXPath 的版本历史是「断代复活」型:1.3 发布于 2008 年,此后项目沉寂十余年,直到 2025 年 4 月才恢复发行 1.4.0。当前可选版本只有这两代:
| 版本 | 状态 | 说明 | 建议 |
|---|---|---|---|
| 1.4.0 | 当前唯一活跃正式版(2025-04 恢复发行) | 本文实测版本,依赖已刷新(commons-parent 81、commons-logging 1.3.5 管理) | 生产环境首选 |
| 1.3 | 历史版本(2008 年) | 断代 17 年,构建生态与依赖陈旧 | 仅存量系统维护,新项目勿用 |
解读:两版之间没有中间版本,从 1.3 升级到 1.4.0 属于跨代升级;新项目一律直接用 1.4.0,存量 1.3 项目升级前建议用本文第四章的最小程序先做回归验证。
3.2 groupId 陷阱:沿用旧坐标 commons-jxpath
JXPath 是 Commons 家族中少数不使用 org.apache.commons groupId 的组件,1.4.0 仍由历史坐标发布。实测坐标结论:
| Maven 坐标 | 可用性 | 说明 |
|---|---|---|
commons-jxpath:commons-jxpath:1.4.0 | ✅ 可用(本文实测) | 历史沿用的旧 groupId,1.4.0 仍由该坐标发布 |
org.apache.commons:commons-jxpath:1.4.0 | ❌ 不存在(404) | 中央仓库该路径下没有构件,照抄 Commons 惯例会解析失败 |
解读:这是引入 JXPath 时最容易踩的坑——多数 Commons 组件(commons-io、commons-lang3 等)都在 org.apache.commons 下,惯性写法会直接 404。本文第二章连通性预检返回的 200 证实了旧坐标 POM 真实存在;4.6 节的依赖列表回显也会再次印证。
3.3 依赖构成:无强制传递依赖
对 1.4.0 的 POM 与依赖做了实测核实(《Ubuntu 22.04 安装 Apache Commons JXPath 指南》4.5 节有完整的依赖树与 POM 片段回显),结论先行:
- 依赖树只有它自己:
mvn dependency:tree仅解析出commons-jxpath:commons-jxpath:jar:1.4.0:compile一行,无任何强制传递依赖。 - commons-logging 1.3.5 只出现在 POM 的
<dependencyManagement>中(仅锁版本,不是实际依赖);实测运行期 classpath 不带它也完全不报错。 - servlet-api / jsp-api 为
provided+optional(仅 JSP/Servlet 场景需要,由 Servlet 运行环境提供)。 - jdom 1.1.3、commons-beanutils 1.10.1 为
optional(JDOM 文档模型等扩展特性按需引入)。 - 没有 xerces 依赖:XML 解析使用 JDK 内置的
com.sun.org.apache.xerces实现。
💡 技术拓展:「对象图导航/XPath 求值」在 Java 生态不止 JXPath 一种实现。常见选项对比——
库 导航模型 特点 适用场景 Commons JXPath XPath 1.0 同时作用于 JavaBean 对象图与 XML DOM 一套语法通吃 Bean 属性/集合与 XML;支持 Pointer、路径创建、变量与扩展函数 需要用同一表达式语法访问 JavaBean 和 XML Jaxen 独立 XPath 引擎,供 dom4j/JDOM/XOM 等树模型适配 XPath 引擎本体,不含 Bean 导航;常作为 dom4j 的底层 已用 dom4j/JDOM 处理 XML,只需 XPath javax.xml.xpath(JDK 内置) JDK 自带 XPath 1.0,面向 DOM/Source 零依赖,但只支持 XML,不支持 JavaBean 导航 仅 XML 求值、不想引第三方库 Commons BeanUtils / PropertyUtils 属性路径字符串( a.b[0].c)按 getter/setter 反射轻量嵌套属性读写,但不支持谓词过滤、函数、XPath 轴 简单嵌套属性取值/赋值、对象属性拷贝 Spring EL(SpEL) 表达式语言,支持属性导航、集合选择投影 功能强但绑定 Spring 体系,表达式非 XPath 方言 Spring 技术栈内的动态取值与条件求值 本文场景需要「同一套 XPath 语法既访问 JavaBean 对象图又访问 XML DOM」,选用 Commons JXPath 1.4.0:它无传递依赖、单 jar 即可运行,且 1.4.0 已于 2025 年恢复维护。
四、在线安装方案(A:Maven 依赖引入)
官方推荐方式:通过 Maven 引入依赖。CentOS 8 上本方案的关键是 JAVA_HOME 与 java 命令的双 JDK 解析:Maven 由 JAVA_HOME 决定用哪个 JDK 编译,而命令行的 java 由系统 alternatives 决定用哪个 JDK 运行,两者要分别确认。
4.1 方案说明与适用场景
本方案先确认系统 Java/Maven 现状,设置 JAVA_HOME 指向 JDK 17,再创建最小 Maven 工程引入 commons-jxpath:commons-jxpath:1.4.0,最后编译并运行一个覆盖核心用法的验证程序——包括用 JDK 17 完整路径绕开系统默认 Java 1.8 的真实踩坑过程。适合可访问中央仓库的场景。
4.2 确认系统 Java 与 Maven 现状
一次性确认默认 java、mvn 使用的 JDK 以及系统里已装的 JDK 目录:
java -version 2>&1; echo ===MVN===; mvn -v 2>&1; echo ===JVM17===; ls /usr/lib/jvm/
输出:
openjdk version "1.8.0_312"
OpenJDK Runtime Environment (build 1.8.0_312-b07)
OpenJDK 64-Bit Server VM (build 25.312-b07, mixed mode)
===MVN===
Apache Maven 3.5.4 (Red Hat 3.5.4-5)
Maven home: /usr/share/maven
Java version: 1.8.0_312, vendor: Red Hat, Inc., runtime: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.312.b07-2.el8_5.x86_64/jre
Default locale: en_US, platform encoding: ANSI_X3.4-1968
OS name: "linux", version: "6.8.0-138-generic", arch: "amd64", family: "unix"
===JVM17===
java
java-1.8.0
java-1.8.0-openjdk
java-1.8.0-openjdk-1.8.0.312.b07-2.el8_5.x86_64
java-17
java-17-openjdk
java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64
java-openjdk
jre
jre-1.8.0
jre-1.8.0-openjdk
jre-1.8.0-openjdk-1.8.0.312.b07-2.el8_5.x86_64
jre-17
jre-17-openjdk
jre-17-openjdk-17.0.1.0.12-2.el8_5.x86_64
jre-openjdk
解读:默认 java 是 1.8.0_312,Maven 也解析到 1.8(Java version: 1.8.0_312);/usr/lib/jvm/ 下同时存在 java-17-openjdk(17.0.1)。本文按 JDK 17 实测,因此后续必须先设置 JAVA_HOME。另外注意 platform encoding: ANSI_X3.4-1968——本环境默认编码为 ASCII,Java 源码含中文注释时需统一 UTF-8(见 4.4 节 pom 配置)。
4.3 设置 JAVA_HOME 指向 JDK 17
设置 JAVA_HOME 并验证 Maven 已切换到 JDK 17:
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk && mvn -v | head -3
输出:
Apache Maven 3.5.4 (Red Hat 3.5.4-5)
Maven home: /usr/share/maven
Java version: 17.0.1, vendor: Red Hat, Inc., runtime: /usr/lib/jvm/java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64
关键点:Java version 变为 17.0.1,说明 Maven 编译将使用 JDK 17。
⚠️ 注意:
export JAVA_HOME只影响 Maven(及其拉起的编译器),不会改变 PATH 上java命令的解析结果——直接敲java仍是 1.8,运行 17 编译出的类会报UnsupportedClassVersionError(4.6 节实测)。运行程序需用$JAVA_HOME/bin/java完整路径。该export仅对当前会话生效;若需持久化,可将export JAVA_HOME=/usr/lib/jvm/java-17-openjdk写入/etc/profile.d/java17.sh并重新登录。
4.4 创建 Maven 工程并引入依赖
创建工程目录与源码目录:
mkdir -p /opt/jxpath-demo/src/main/java/demo
/opt/jxpath-demo/pom.xml 完整内容(与 Ubuntu 篇示例工程仅 artifactId 不同):
<?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>jxpath-centos-demo</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>commons-jxpath</groupId>
<artifactId>commons-jxpath</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<release>17</release>
</configuration>
</plugin>
</plugins>
</build>
</project>
逐项说明:groupId 用旧坐标 commons-jxpath(第三章的选型要点,写成 org.apache.commons 会 404);project.build.sourceEncoding 设为 UTF-8(本环境 mvn -v 显示平台编码为 ANSI_X3.4-1968,源码含中文注释时必须显式指定,否则 javac 报 unmappable character);maven-compiler-plugin 用 <release>17</release> 按 JDK 17 编译(因此 Maven 必须运行在 JDK 17 上,即 4.3 节的 JAVA_HOME);依赖仅声明 JXPath 一个。
4.5 编写验证程序
验证程序 /opt/jxpath-demo/src/main/java/demo/BeanNavMain.java 完整内容(Company/Employee 两层对象图,覆盖点式路径报错、基本取值、谓词、集合遍历与变量):
package demo;
import org.apache.commons.jxpath.JXPathContext;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Minimal bean-navigation demo for the CentOS 8 environment.
*/
public class BeanNavMain {
public static class Employee {
private final String name;
private final int age;
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Employee{name=" + name + ", age=" + age + "}";
}
}
public static class Company {
private final String name;
private final List<Employee> employees = new ArrayList<>();
public Company(String name) {
this.name = name;
}
public String getName() {
return name;
}
public List<Employee> getEmployees() {
return employees;
}
}
public static void main(String[] args) {
Company company = new Company("Acme Corp");
company.getEmployees().add(new Employee("Alice", 28));
company.getEmployees().add(new Employee("Bob", 35));
company.getEmployees().add(new Employee("Carol", 41));
JXPathContext ctx = JXPathContext.newContext(company);
try {
System.out.println("getValue(\"employees[1].name\") = " + ctx.getValue("employees[1].name"));
} catch (Exception e) {
System.out.println("getValue(\"employees[1].name\") threw " + e.getClass().getName());
System.out.println(" message: " + e.getMessage());
}
System.out.println("getValue(\"name\") = " + ctx.getValue("name"));
System.out.println("getValue(\"employees[1]/name\") = " + ctx.getValue("employees[1]/name"));
System.out.println("getValue(\"employees[age > 30]/name\") = " + ctx.getValue("employees[age > 30]/name"));
Iterator<?> it = ctx.iterate("employees");
while (it.hasNext()) {
System.out.println("iterate -> " + it.next());
}
ctx.getVariables().declareVariable("minAge", Integer.valueOf(30));
Iterator<?> seniors = ctx.iterate("employees[age > $minAge]/name");
while (seniors.hasNext()) {
System.out.println("senior(name) -> " + seniors.next());
}
}
}
说明:程序故意保留了对点式路径 employees[1].name 的尝试并捕获异常打印,用于验证 JXPath 的语法约束(结果见 4.6 节最终运行输出第一组)。
4.6 编译与运行验证
第一步:编译(JAVA_HOME 必须已指向 JDK 17):
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk && cd /opt/jxpath-demo && mvn -B compile 2>&1 | tail -12
输出节选(实测 tail -12):
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /opt/jxpath-demo/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.11.0:compile (default-compile) @ jxpath-centos-demo ---
[INFO] Changes detected - recompiling the module! :dependency
[INFO] Compiling 1 source file with javac [debug release 17] to target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.883 s
[INFO] Finished at: 2026-10-14T10:35:27Z
[INFO] ------------------------------------------------------------------------
第二步:依赖核实(确认解析到的正是 1.4.0 旧坐标构件):
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk && mvn -v | head -3; echo ===LIST===; cd /opt/jxpath-demo && mvn -B dependency:list 2>&1 | sed -n "/The following files/,/BUILD SUCCESS/p" | grep jxpath
输出:
Apache Maven 3.5.4 (Red Hat 3.5.4-5)
Maven home: /usr/share/maven
Java version: 17.0.1, vendor: Red Hat, Inc., runtime: /usr/lib/jvm/java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64
===LIST===
[INFO] commons-jxpath:commons-jxpath:jar:1.4.0:compile
依赖列表仅 commons-jxpath:commons-jxpath:jar:1.4.0:compile 一行,与 Ubuntu 环境完全一致。
第三步:运行(先踩真实坑)——生成 classpath 后直接用 PATH 上的 java 运行,报 UnsupportedClassVersionError:
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk && cd /opt/jxpath-demo && mvn -B dependency:build-classpath -Dmdep.outputFile=/tmp/cp.txt -q 2>&1 | tail -2; echo CP=$(cat /tmp/cp.txt); java -cp target/classes:$(cat /tmp/cp.txt) demo.BeanNavMain 2>&1
输出:
CP=/root/.m2/repository/commons-jxpath/commons-jxpath/1.4.0/commons-jxpath-1.4.0.jar
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.UnsupportedClassVersionError: demo/BeanNavMain has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 52.0
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:55)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:606)
at java.lang.ClassLoader.loadClass(ClassLoader.java:566)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:366)
at java.lang.ClassLoader.loadClass(ClassLoader.java:563)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:761)
解读:classpath 生成正常(CP= 行仅有 JXPath 一个 jar),报错原因是 PATH 上的 java 仍是 1.8(class file 52.0),而类是 JDK 17 编译的(class file 61.0)。JAVA_HOME 不改变 java 命令的解析——这正是 4.3 节 ⚠️ 提到的双 JDK 解析问题。
第四步:改用 $JAVA_HOME/bin/java 正确运行(先重新编译一次确保产物最新,再运行):
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk && cd /opt/jxpath-demo && mvn -B -q compile 2>&1 | tail -3; $JAVA_HOME/bin/java -cp target/classes:$(cat /tmp/cp.txt) demo.BeanNavMain 2>&1
输出:
getValue("employees[1].name") threw org.apache.commons.jxpath.JXPathInvalidSyntaxException
message: Invalid XPath: 'employees[1].name'. Syntax error after: 'employees[1]'
getValue("name") = Acme Corp
getValue("employees[1]/name") = Alice
getValue("employees[age > 30]/name") = Bob
iterate -> Employee{name=Alice, age=28}
iterate -> Employee{name=Bob, age=35}
iterate -> Employee{name=Carol, age=41}
senior(name) -> Bob
senior(name) -> Carol
验证点:-q 静默编译无报错输出,随后 5 组用例全部符合预期——点式路径按预期抛 JXPathInvalidSyntaxException(预期行为,见第八章 Q2)、employees[1]/name 取到 Alice(XPath 下标 1-based,employees[1] 对应 List.get(0))、谓词过滤取到 Bob、iterate 遍历出 3 个对象、变量 $minAge 过滤出 Bob 与 Carol。JXPath 行为与 Ubuntu 环境完全一致,跨发行版无差异。逐条语法解读见《Apache Commons JXPath 1.4.0 常用 API 与 XPath 语法详解》。
五、离线安装方案(B:官方二进制包)
适合内网隔离、无法访问 Maven 中央仓库的环境。JXPath 1.4.0 无传递依赖,官方二进制包解压后仅靠主 jar 一个文件即可编译运行,无需补任何第三方 jar;CentOS 8 上同样要使用 JDK 17 完整路径。
5.1 方案说明与适用场景
官方 commons-jxpath-1.4.0-bin.tar.gz 内含 JXPath 自身的 5 个 jar(主 jar、tests、test-sources、sources、javadoc)与 LICENSE/NOTICE/apidocs 文档,没有 lib/ 或 ext/ 目录、不附带 commons-logging。本方案流程:下载 → 解压 → 用主 jar 编译一个最小程序 → 运行验证。由于 4.6 节已实测 PATH 上的 java 是 1.8,本章编译运行统一使用 $JAVA_HOME/bin/javac、$JAVA_HOME/bin/java。
5.2 下载与解压
用 curl 下载官方二进制包并解压到 /opt/jxpath-dist(--strip-components=1 去掉包内一层目录):
cd /opt && curl -sO https://downloads.apache.org/commons/jxpath/binaries/commons-jxpath-1.4.0-bin.tar.gz && ls -l commons-jxpath-1.4.0-bin.tar.gz && mkdir -p /opt/jxpath-dist && tar xzf commons-jxpath-1.4.0-bin.tar.gz -C /opt/jxpath-dist --strip-components=1 && find /opt/jxpath-dist -name "*.jar" | sort
输出:
-rw-r--r-- 1 root root 3374636 Oct 14 10:33 commons-jxpath-1.4.0-bin.tar.gz
/opt/jxpath-dist/commons-jxpath-1.4.0-javadoc.jar
/opt/jxpath-dist/commons-jxpath-1.4.0-sources.jar
/opt/jxpath-dist/commons-jxpath-1.4.0-test-sources.jar
/opt/jxpath-dist/commons-jxpath-1.4.0-tests.jar
/opt/jxpath-dist/commons-jxpath-1.4.0.jar
解读:包大小实测 3374636 字节(约 3.4 MB);5 个 jar 中日常只需 commons-jxpath-1.4.0.jar 主 jar,其余为测试、源码与 javadoc 附属包。若系统未装 wget,wget 命令会直接报 bash: wget: command not found(见第八章 Q4),统一用 curl 最稳妥。
5.3 解压目录结构
确认发行包的完整结构:
ls /opt/jxpath-dist
输出:
LICENSE.txt
NOTICE.txt
apidocs
commons-jxpath-1.4.0-javadoc.jar
commons-jxpath-1.4.0-sources.jar
commons-jxpath-1.4.0-test-sources.jar
commons-jxpath-1.4.0-tests.jar
commons-jxpath-1.4.0.jar
解读:目录里只有许可证、HTML 版 javadoc(apidocs/)与 5 个 jar——没有 lib/、ext/ 目录,不带 commons-logging。这不是缺陷:1.4.0 无强制传递依赖(见 3.3 节),主 jar 单独就能跑,5.4 节立即验证。
5.4 最小程序编译运行验证
创建演示目录与最小程序 /opt/jxpath-dist-demo/Main.java(无包名,javac/java 直跑):
import org.apache.commons.jxpath.JXPathContext;
import java.util.ArrayList;
import java.util.List;
/**
* Minimal demo for the official binary distribution (commons-jxpath-1.4.0-bin.tar.gz).
* Compiled and run with plain javac/java + -cp.
*/
public class Main {
public static class Address {
private final String city;
public Address(String city) {
this.city = city;
}
public String getCity() {
return city;
}
}
public static class Employee {
private final String name;
private final int age;
private final Address address;
public Employee(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public Address getAddress() {
return address;
}
}
public static class Company {
private final String name;
private final List<Employee> employees = new ArrayList<>();
public Company(String name) {
this.name = name;
}
public String getName() {
return name;
}
public List<Employee> getEmployees() {
return employees;
}
}
public static void main(String[] args) {
Company company = new Company("Acme Corp");
company.getEmployees().add(new Employee("Alice", 28, new Address("Beijing")));
company.getEmployees().add(new Employee("Bob", 35, new Address("Shanghai")));
JXPathContext ctx = JXPathContext.newContext(company);
System.out.println("name = " + ctx.getValue("name"));
System.out.println("employees[1]/name = " + ctx.getValue("employees[1]/name"));
System.out.println("employees[age > 30]/name = " + ctx.getValue("employees[age > 30]/name"));
System.out.println("employees/address/city = " + ctx.getValue("employees/address/city"));
}
}
用 JDK 17 完整路径编译并运行(classpath 只有 JXPath 主 jar 一个文件):
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
mkdir -p /opt/jxpath-dist-demo
cd /opt/jxpath-dist-demo
$JAVA_HOME/bin/javac -cp /opt/jxpath-dist/commons-jxpath-1.4.0.jar Main.java && echo JAVAC_OK
$JAVA_HOME/bin/java -cp .:/opt/jxpath-dist/commons-jxpath-1.4.0.jar Main 2>&1
输出:
JAVAC_OK
name = Acme Corp
employees[1]/name = Alice
employees[age > 30]/name = Bob
employees/address/city = Beijing
验证点:JAVAC_OK 确认仅凭主 jar 即可编译;运行输出 4 行全部正确——employees[1]/name 取到第 1 个员工 Alice、谓词 age > 30 取到 Bob、多级路径 employees/address/city 取到北京。全程无 NoClassDefFoundError,证明不带 commons-logging 完全可行。这里刻意用 $JAVA_HOME/bin/javac、$JAVA_HOME/bin/java:PATH 上的 javac/java 仍是 1.8(4.6 节已实测 java 的解析结果),JDK 17 编译的产物绝不能用 1.8 运行。
⚠️ 注意:若把本示例源码写成点式路径
employees[1].name,运行会抛JXPathInvalidSyntaxException: Invalid XPath: 'employees[1].name'. Syntax error after: 'employees[1]'(与方案 A 实测一致),必须写employees[1]/name。
六、多方案对照与选择建议
两种方案各有取舍,本节汇总关键差异并给出选型建议。
| 维度 | 方案 A:Maven 依赖 | 方案 B:官方二进制包 |
|---|---|---|
| 是否需联网 | 构建时需访问中央仓库 | 仅下载阶段需联网,之后完全离线 |
| 获取坐标 | commons-jxpath:commons-jxpath:1.4.0(旧 groupId) | downloads.apache.org 的 binaries/ 子目录 |
| 依赖完整性 | 自动解析(实测无传递依赖,同样只有单 jar) | 主 jar 即全部,无需补 jar |
| 附带产物 | 仅主 jar(sources/javadoc 需单独在 IDE 拉取) | 附带 sources/javadoc/tests jar 与 apidocs 文档 |
| JDK 要求 | Maven 需 JAVA_HOME 指向 JDK 17 | 编译运行均建议 $JAVA_HOME/bin 完整路径 |
| 验证结果 | 与 B 一致 | 与 A 一致 |
选择建议:可联网优先方案 A(版本管理清晰,是工程项目的默认形态);内网隔离或只想快速试用选方案 B(一次下载 3.4 MB,解压即用,还自带源码与文档)。CentOS 8 上无论哪种方案,都要落实 4.3 节的 JAVA_HOME 与「运行用 JDK 17 完整路径」两条纪律。两方案的运行结果完全一致,可放心互换。
七、配置说明
JXPath 是纯 Java 进程内库,无独立配置文件,CentOS 8 环境下需要关注的「配置」集中在 JDK 选择与依赖坐标,本节逐项说明。
JAVA_HOME(关键):CentOS 8 默认 Java 为 1.8,export JAVA_HOME=/usr/lib/jvm/java-17-openjdk后 Maven 才会用 17 编译(4.3 节实测验证)。该设置仅当前会话生效,持久化可写入/etc/profile.d/java17.sh(内容一行:export JAVA_HOME=/usr/lib/jvm/java-17-openjdk),重新登录生效。- 运行时 JDK 选择:
JAVA_HOME不影响 PATH 上java的解析,运行 17 编译的类必须用$JAVA_HOME/bin/java(4.6 节第三步的UnsupportedClassVersionError即反例)。 - 源码编码:
project.build.sourceEncoding设为 UTF-8;本环境平台编码为 ANSI_X3.4-1968,源码含中文注释时若缺该配置,javac会报unmappable character。 - 依赖坐标(关键):固定写旧 groupId
commons-jxpath:commons-jxpath:1.4.0;org.apache.commons下无此构件。 - optional 依赖按需引入:使用 JDOM 文档模型等扩展特性时,再显式添加
org.jdom:jdom:1.1.3或commons-beanutils:commons-beanutils:1.10.1;默认的 Bean/DOM 导航不需要它们(见 3.3 节)。 - 日志:1.4.0 的 POM 仅在
dependencyManagement中锁定commons-logging:1.3.5的版本,基本用法不强制该 jar(4.6/5.4 节实测运行期无它也不报错);若宿主应用需要日志输出,自行在依赖中添加commons-logging即可。
八、常见问题(FAQ)
Q1:运行报 UnsupportedClassVersionError(class file version 61.0 对 52.0)怎么办?
JDK 17 编译的类被 1.8 运行所致:JAVA_HOME 只影响 Maven,PATH 上的 java 仍是 1.8。完整实测报错见 4.6 节第三步。解决:运行时改用 JDK 17 完整路径:
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk && cd /opt/jxpath-demo && $JAVA_HOME/bin/java -cp target/classes:$(cat /tmp/cp.txt) demo.BeanNavMain 2>&1
正确运行后的完整回显见 4.6 节第四步。也可把 $JAVA_HOME/bin 置于 PATH 最前,或用 alternatives --config java 把系统默认 java 切到 17(会影响整机所有用户,按需选择)。
Q2:执行 XPath 报 JXPathInvalidSyntaxException: Invalid XPath: 'employees[1].name' 怎么办?
JXPath 的 XPath 方言不支持点式续写:谓词方括号或下标之后必须用 / 访问子属性。实测报错:
getValue("employees[1].name") threw org.apache.commons.jxpath.JXPathInvalidSyntaxException
message: Invalid XPath: 'employees[1].name'. Syntax error after: 'employees[1]'
把点改成斜杠即可(4.6 节第四步实测):
getValue("employees[1]/name") = Alice
Q3:按 org.apache.commons:commons-jxpath 引依赖报找不到构件怎么办?
中央仓库该路径下没有 JXPath 构件(404)。JXPath 至今沿用旧 groupId,正确坐标为 commons-jxpath:commons-jxpath:1.4.0。可用第二章的连通性预检命令验证:旧坐标 POM URL 返回 200;把 URL 中的 commons-jxpath/commons-jxpath 换成 org/apache/commons/commons-jxpath 再探测即无此构件。
Q4:下载时提示 wget: command not found 怎么办?
最小化安装的系统可能没有预装 wget,改用 curl -sO <URL>(或先 dnf install -y wget)即可,5.2 节的下载命令即为 curl 版本。类似的,若 javac/java 解析到 1.8,请一律改用 $JAVA_HOME/bin/javac、$JAVA_HOME/bin/java(见 Q1)。
Q5:mvn compile 报 invalid target release: 17 怎么办?
Maven 运行在低于 17 的 JDK 上(本环境默认 1.8)且工程配置了 <release>17</release>。执行前先设置 JAVA_HOME 并复核:
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk && mvn -v | head -3
输出:
Apache Maven 3.5.4 (Red Hat 3.5.4-5)
Maven home: /usr/share/maven
Java version: 17.0.1, vendor: Red Hat, Inc., runtime: /usr/lib/jvm/java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64
Java version 为 17 后再编译即可(4.6 节第一步实测 BUILD SUCCESS)。
九、卸载与清理
JXPath 为纯 Java 库,不做系统级安装,删除工程目录、发行包与本地仓库构件即可完全清理:
rm -rf /opt/jxpath-demo /opt/jxpath-dist /opt/jxpath-dist-demo /opt/commons-jxpath-1.4.0-bin.tar.gz
rm -rf /root/.m2/repository/commons-jxpath
ls -d /opt/jxpath-demo /opt/jxpath-dist /opt/jxpath-dist-demo /root/.m2/repository/commons-jxpath 2>/dev/null || echo "jxpath all removed"
输出(目录与构件均已删除时):
jxpath all removed
如写了 /etc/profile.d/java17.sh 持久化 JAVA_HOME,一并删除即可。
⚠️ 注意:JDK 与 Maven 属基础环境,不随本文卸载;如需一并移除,用
dnf remove -y java-17-openjdk-devel maven并自行确认影响范围。
十、参考链接
- Apache Commons JXPath 官方主页:https://commons.apache.org/proper/commons-jxpath/
- 官方发行下载目录:https://downloads.apache.org/commons/jxpath/
- Maven 中央仓库坐标目录(旧 groupId):https://repo.maven.apache.org/maven2/commons-jxpath/commons-jxpath/
- JXPath 用户指南(User Guide):https://commons.apache.org/proper/commons-jxpath/userguide.html
- JXPath JavaDoc API 文档:https://commons.apache.org/proper/commons-jxpath/apidocs/index.html