CentOS 8 安装 Apache Commons JXPath 指南

在 CentOS 8 上从零引入 Apache Commons JXPath 1.4.0:JDK 8 与 17 并存下的 JAVA_HOME 配置、Maven 在线依赖与官方二进制包两种安装方案及 UnsupportedClassVersionError 排障,全部命令附真实回显。

Apache Commons JXPathApache Commons JXPath2026/10/14

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」。

二、前置条件

在开始安装前,请确认以下条件满足,否则后续步骤会因权限或网络问题中断。

  1. root 权限或 sudo:需要在 /opt 下创建目录并写入文件。
  2. 网络可达:需要访问 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 可用)。

  1. 磁盘空间:官方二进制包实测 3,374,636 字节(约 3.4 MB),加上 Maven 本地仓库缓存建议预留 ≥ 200 MB。
  2. 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 JXPathXPath 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 并自行确认影响范围。

十、参考链接

  1. Apache Commons JXPath 官方主页:https://commons.apache.org/proper/commons-jxpath/
  2. 官方发行下载目录:https://downloads.apache.org/commons/jxpath/
  3. Maven 中央仓库坐标目录(旧 groupId):https://repo.maven.apache.org/maven2/commons-jxpath/commons-jxpath/
  4. JXPath 用户指南(User Guide):https://commons.apache.org/proper/commons-jxpath/userguide.html
  5. JXPath JavaDoc API 文档:https://commons.apache.org/proper/commons-jxpath/apidocs/index.html