Ubuntu 22.04 安装 Apache Johnzon 指南

在 Ubuntu 22.04 上安装 OpenJDK 17 与 Maven 3.9.9,通过 Maven 引入 Apache Johnzon 2.2.0(JSON-P/JSON-B/Mapper)依赖,编译打包并运行真实示例程序的全流程集成指南。

Apache JohnzonApache Johnzon安装部署JavaApacheUbuntu 22.042026/10/12

Ubuntu 22.04 安装 Apache Johnzon 指南

目标:Apache Johnzon 是 Apache 软件基金会的 JSON 处理库(JSR-353/JSR-374/JSR-367 参考实现),并非可独立启动的守护进程,因此本文以「集成/环境搭建」形态呈现——从零安装 OpenJDK 17 与 Maven 3.9.9,用 Maven 引入 Johnzon 2.2.0 依赖,真实编译打包并运行 JSON-P/JSON-B/Mapper 示例程序,采集真实回显。已在 Ubuntu 22.04.5 LTS(x86_64)实测通过。

一、环境信息

  • 操作系统:Ubuntu 22.04.5 LTS,Kernel 6.8.0-138-generic,架构 x86_64(amd64)
  • OpenJDK 17:17.0.2(build 17.0.2+8-86,安装目录 /opt/java/jdk-17.0.2)
  • Apache Maven:3.9.9(安装目录 /opt/maven)
  • Johnzon:2.2.0(Maven Central 当前最新稳定版)
  • Jakarta API:jakarta.json-api 2.1.3、jakarta.json.bind-api 3.0.1(随依赖引入)
  • 示例工作目录:/opt/johnzon-demo
  • Maven 镜像:阿里云 https://maven.aliyun.com/repository/public

二、前置条件

  • 已具备 root 或 sudo 权限,可执行 apt-get install、编辑 /etc/profile.d/。
  • 服务器可联网访问 Maven 仓库(本文实测走阿里云镜像)与华为云开源镜像站(用于下载 JDK/Maven 二进制包)。
  • 磁盘剩余空间不少于 2 GB(JDK 解压约 310 MB、Maven 约 10 MB、本地 Maven 仓库约 60 MB)。

三、版本选型说明

Johnzon 2.2.0 为 Maven Central 当前最新稳定版(实测查询 https://repo.maven.apache.org/maven2/org/apache/johnzon/johnzon-core/maven-metadata.xml,<latest> 与 <release> 均为 2.2.0)。Johnzon 按「模块 jar」分发,各模块坐标如下:

模块Maven 坐标(groupId : artifactId)本次实测版本说明
JSON-P 核心org.apache.johnzon : johnzon-core2.2.0Jakarta JSON Processing 实现(解析/生成/指针)
Mapperorg.apache.johnzon : johnzon-mapper2.2.0POJO ↔ JSON 对象映射引擎
JSON-Borg.apache.johnzon : johnzon-jsonb2.2.0Jakarta JSON Binding 实现(含 JAX-RS Provider)
JSON-P APIjakarta.json : jakarta.json-api2.1.3JSON Processing API(Johnzon 声明为 provided,须显式引入)
JSON-B APIjakarta.json.bind : jakarta.json.bind-api3.0.1JSON Binding API(Johnzon 声明为 provided,须显式引入)

选型要点:

  • Johnzon 2.x 使用 jakarta.json.* 命名空间(Jakarta EE 9+),适配 Tomcat 10.x/CXF 4.x 等新栈;老应用(javax.json.*)须退回 Johnzon 1.2.x 系列。
  • Johnzon 2.2.0 编译目标为 Java 11(父 POM maven.compiler.release=11),JDK 11 及以上均可运行,本文使用 JDK 17。
  • johnzon-core/mapper/jsonb 三个模块的 jar 清单实测均为 Bundle-Version: 2.2.0,可作为版本核对依据。

四、部署步骤(集成与编译运行)

4.1 方案 A:华为云镜像 tar.gz 安装 OpenJDK 17 与 Maven 3.9.9(推荐)

华为云镜像站在国内网络实测下载速度最快(约 8.9 MB/s)。下载并解压 OpenJDK 17.0.2:

cd /tmp
curl -L -o jdk17.tar.gz "https://mirrors.huaweicloud.com/openjdk/17.0.2/openjdk-17.0.2_linux-x64_bin.tar.gz"
mkdir -p /opt/java
tar -xzf jdk17.tar.gz -C /opt/java

下载并解压 Maven 3.9.9:

cd /tmp
curl -L -o maven.tar.gz "https://mirrors.huaweicloud.com/apache/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.tar.gz"
tar -xzf maven.tar.gz -C /opt
mv /opt/apache-maven-3.9.9 /opt/maven

写入环境变量(/etc/profile.d/javadev.sh):

cat > /etc/profile.d/javadev.sh <<'EOF'
export JAVA_HOME=/opt/java/jdk-17.0.2
export MAVEN_HOME=/opt/maven
export PATH=$JAVA_HOME/bin:$MAVEN_HOME/bin:$PATH
EOF
source /etc/profile.d/javadev.sh

建立全局软链接,方便任意用户直接调用:

ln -sf /opt/java/jdk-17.0.2/bin/java /usr/local/bin/java
ln -sf /opt/java/jdk-17.0.2/bin/javac /usr/local/bin/javac
ln -sf /opt/maven/bin/mvn /usr/local/bin/mvn

验证 JDK 与 Maven:

java -version

真实回显:

openjdk version "17.0.2" 2022-01-18
OpenJDK Runtime Environment (build 17.0.2+8-86)
OpenJDK 64-Bit Server VM (build 17.0.2+8-86, mixed mode, sharing)
mvn -version

真实回显:

Apache Maven 3.9.9 (8e8579a9e76f7d015ee5ec7bfcdc97d260186937)
Maven home: /opt/maven
Java version: 17.0.2, vendor: Oracle Corporation, runtime: /opt/java/jdk-17.0.2
Default locale: en_US, platform encoding: ANSI_X3.4-1968
OS name: "linux", version: "6.8.0-138-generic", arch: "amd64", family: "unix"

💡 说明:platform encoding 显示 ANSI_X3.4-1968(POSIX locale)时,建议按 4.3 节统一设置 UTF-8,避免中文 JSON 乱码。

4.2 方案 B:apt 在线安装 OpenJDK 17 与 Maven(备用)

Ubuntu 22.04 官方仓库自带 JDK 17 与 Maven,适合可直接访问 apt 源的环境:

apt-get update -y
apt-get install -y openjdk-17-jdk-headless maven

安装前可先查询仓库内实际版本(实测输出):

apt-cache policy openjdk-17-jdk-headless | head -4

真实回显:

openjdk-17-jdk-headless:
  Installed: (none)
  Candidate: 17.0.20.1+1-1~22.04
  Version table:
apt-cache policy maven | head -4

真实回显:

maven:
  Installed: (none)
  Candidate: 3.6.3-5
  Version table:

⚠️ 注意:apt 源中 Maven 为 3.6.3,功能上足以编译运行 Johnzon 2.2.0;如需 Maven 3.9.x 的新特性,按方案 A 安装二进制包。两方案并存时用 update-alternatives --config java 或 JAVA_HOME 切换 JDK。

4.3 Maven 镜像加速与编码配置

国内网络直连 Maven Central 较慢,配置阿里云镜像加速(实测依赖下载走该镜像)。创建 /root/.m2/settings.xml:

mkdir -p /root/.m2
cat > /root/.m2/settings.xml <<'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0">
  <mirrors>
    <mirror>
      <id>aliyunmaven</id>
      <mirrorOf>central</mirrorOf>
      <name>Aliyun Maven Central Mirror</name>
      <url>https://maven.aliyun.com/repository/public</url>
    </mirror>
  </mirrors>
</settings>
EOF

同时在 /etc/profile.d/javadev.sh 中追加 UTF-8 编码(避免中文乱码):

echo 'export JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8' >> /etc/profile.d/javadev.sh
source /etc/profile.d/javadev.sh

4.4 创建 Johnzon 演示工程并引入依赖

建立目录结构:

mkdir -p /opt/johnzon-demo/src/main/java/demo

创建工程描述文件 /opt/johnzon-demo/pom.xml。关键点:Johnzon 2.2.0 将 jakarta.json-api 与 jakarta.json.bind-api 声明为 provided,不会传递引入,必须显式添加:

<?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>johnzon-demo</artifactId>
  <version>1.0.0</version>
  <packaging>jar</packaging>
  <properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <johnzon.version>2.2.0</johnzon.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>jakarta.json</groupId>
      <artifactId>jakarta.json-api</artifactId>
      <version>2.1.3</version>
    </dependency>
    <dependency>
      <groupId>jakarta.json.bind</groupId>
      <artifactId>jakarta.json.bind-api</artifactId>
      <version>3.0.1</version>
    </dependency>
    <dependency>
      <groupId>org.apache.johnzon</groupId>
      <artifactId>johnzon-core</artifactId>
      <version>${johnzon.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.johnzon</groupId>
      <artifactId>johnzon-mapper</artifactId>
      <version>${johnzon.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.johnzon</groupId>
      <artifactId>johnzon-jsonb</artifactId>
      <version>${johnzon.version}</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.5.2</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals><goal>shade</goal></goals>
            <configuration>
              <transformers>
                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                  <mainClass>demo.JsonpDemo</mainClass>
                </transformer>
              </transformers>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

编写一个 JSON-P 演示主类 /opt/johnzon-demo/src/main/java/demo/JsonpDemo.java(构建 JsonObject、美化输出、JsonReader 解析):

package demo;

import jakarta.json.Json;
import jakarta.json.JsonObject;
import jakarta.json.JsonReader;
import jakarta.json.JsonWriter;
import jakarta.json.JsonWriterFactory;
import jakarta.json.stream.JsonGenerator;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Map;

public class JsonpDemo {
    public static void main(String[] args) {
        // 1. 构建 JsonObject
        JsonObject obj = Json.createObjectBuilder()
                .add("id", 1001)
                .add("name", "johnzon")
                .add("price", 49.9)
                .add("tags", Json.createArrayBuilder().add("json").add("parser").build())
                .add("author", Json.createObjectBuilder().add("name", "Apache").add("site", "johnzon.apache.org"))
                .build();
        System.out.println("[build] compact = " + obj.toString());

        // 2. 美化输出
        JsonWriterFactory wf = Json.createWriterFactory(Map.of(JsonGenerator.PRETTY_PRINTING, true));
        StringWriter sw = new StringWriter();
        try (JsonWriter w = wf.createWriter(sw)) {
            w.writeObject(obj);
        }
        System.out.println("[pretty]");
        System.out.println(sw.toString());

        // 3. JsonReader 解析
        String text = "{\"user\":\"root\",\"port\":22,\"roles\":[\"admin\",\"dev\"]}";
        try (JsonReader r = Json.createReader(new StringReader(text))) {
            JsonObject parsed = r.readObject();
            System.out.println("[parse] user   = " + parsed.getString("user"));
            System.out.println("[parse] port   = " + parsed.getInt("port"));
            System.out.println("[parse] roles  = " + parsed.getJsonArray("roles"));
        }
    }
}

4.5 解析依赖(验证真实版本)

cd /opt/johnzon-demo
mvn dependency:tree 2>&1 | grep -E "johnzon|jakarta.json"

真实回显:

[INFO] +- jakarta.json:jakarta.json-api:jar:2.1.3:compile
[INFO] +- jakarta.json.bind:jakarta.json.bind-api:jar:3.0.1:compile
[INFO] +- org.apache.johnzon:johnzon-core:jar:2.2.0:compile
[INFO] +- org.apache.johnzon:johnzon-mapper:jar:2.2.0:compile
[INFO] \- org.apache.johnzon:johnzon-jsonb:jar:2.2.0:compile

4.6 编译打包(shade fat-jar)

cd /opt/johnzon-demo
MAVEN_OPTS="-Xms256m -Xmx512m" mvn package -DskipTests

真实回显(关键行):

[INFO] Building jar: /opt/johnzon-demo/target/johnzon-demo-1.0.0.jar
[INFO] --- maven-shade-plugin:3.5.2:shade (default) @ johnzon-demo ---
[INFO] Including jakarta.json:jakarta.json-api:jar:2.1.3 in the shaded jar.
[INFO] Including jakarta.json.bind:jakarta.json.bind-api:jar:3.0.1 in the shaded jar.
[INFO] Including org.apache.johnzon:johnzon-core:jar:2.2.0 in the shaded jar.
[INFO] Including org.apache.johnzon:johnzon-mapper:jar:2.2.0 in the shaded jar.
[INFO] Including org.apache.johnzon:johnzon-jsonb:jar:2.2.0 in the shaded jar.
[INFO] Replacing original artifact with shaded artifact.
[INFO] Replacing /opt/johnzon-demo/target/johnzon-demo-1.0.0.jar with /opt/johnzon-demo/target/johnzon-demo-1.0.0-shaded.jar
[INFO] BUILD SUCCESS

查看产物大小:

ls -lh target/*.jar

真实回显:

-rw-r--r-- 1 root root 635K Oct 11 13:05 target/johnzon-demo-1.0.0.jar
-rw-r--r-- 1 root root  12K Oct 11 13:05 target/original-johnzon-demo-1.0.0.jar

4.7 运行示例并验证

以 256–512MB 堆限制运行 fat-jar:

cd /opt/johnzon-demo
java -Xms256m -Xmx512m -Dfile.encoding=UTF-8 -jar target/johnzon-demo-1.0.0.jar

真实回显:

[build] compact = {"id":1001,"name":"johnzon","price":49.9,"tags":["json","parser"],"author":{"name":"Apache","site":"johnzon.apache.org"}}
[pretty]
{
  "id":1001,
  "name":"johnzon",
  "price":49.9,
  "tags":[
    "json",
    "parser"
  ],
  "author":{
    "name":"Apache",
    "site":"johnzon.apache.org"
  }
}
[parse] user   = root
[parse] port   = 22
[parse] roles  = ["admin","dev"]

验证 JVM 堆上限真实生效(512MB = 536870912 字节):

java -Xms256m -Xmx512m -XX:+PrintFlagsFinal -version 2>/dev/null | grep MaxHeapSize

真实回显:

   size_t MaxHeapSize                              = 536870912                                 {product} {command line}

核对依赖 jar 自带的版本清单:

cd /tmp
jar xf /root/.m2/repository/org/apache/johnzon/johnzon-core/2.2.0/johnzon-core-2.2.0.jar META-INF/MANIFEST.MF
grep -E "Bundle-SymbolicName|Bundle-Version" META-INF/MANIFEST.MF

真实回显:

Bundle-SymbolicName: org.apache.johnzon.core
Bundle-Version: 2.2.0
Implementation-Version: 2.2.0

五、配置说明

  • 依赖配置(pom.xml):三模块按需引入——只做 JSON 解析/生成用 johnzon-core;POJO 映射加 johnzon-mapper;标准 JSON-B 绑定用 johnzon-jsonb。jakarta 两个 API jar 必须显式声明(Johnzon 侧为 provided)。
  • Maven 设置(/root/.m2/settings.xml):<mirrorOf>central</mirrorOf> 指向阿里云镜像加速依赖下载。
  • 编译级别:Johnzon 2.2.0 要求 maven.compiler.release >= 11,本文取 17。
  • JVM 参数:演示程序以 -Xms256m -Xmx512m 运行限制堆内存;Johnzon 是库,无独立守护进程,内存由上层 Java 进程承载,Maven 构建阶段建议同步设置 MAVEN_OPTS="-Xms256m -Xmx512m"。
  • 编码:涉及中文时设置 JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8,并在生成器工厂配置 UTF-8(见《Apache Johnzon 配置参数详解》)。

⚠️ 注意:Johnzon 不是守护进程,没有 systemd 服务、没有监听端口、没有数据目录。「安装」即「在工程中引入依赖并用 Maven 编译」,产物为 jar,交由上层应用进程加载。

六、注意事项

  • Jakarta 命名空间:Johnzon 2.x 全部 API 位于 jakarta.json.* / jakarta.json.bind.*,与旧 javax.json.* 代码不兼容;混用会导致 ClassNotFoundError。
  • provided 依赖:jakarta.json-api/jakarta.json.bind-api 不随 Johnzon 传递引入,漏配时报 class file for jakarta.json.JsonValue not found。
  • SPI 自动接管:johnzon-core 在 META-INF/services/jakarta.json.spi.JsonProvider 注册了 org.apache.johnzon.core.JsonProviderImpl,加入 classpath 后 JsonProvider.provider() 即返回 Johnzon 实现。
  • 多版本并存:本地仓库中可同时缓存 2.2.0 与 1.2.x,但同一工程 classpath 只能有一个大版本,避免符号冲突。

七、常见问题

Q1:编译报 class file for jakarta.json.JsonValue not found

Johnzon 2.2.0 将 jakarta API 声明为 provided,不传递。在 pom.xml 显式添加 jakarta.json:jakarta.json-api:2.1.3(用 JSON-B 再加 jakarta.json.bind:jakarta.json.bind-api:3.0.1),见 4.4 节。

Q2:Maven 下载依赖极慢或卡住

配置阿里云镜像(见 4.3 节)后执行 mvn -U dependency:resolve 强制刷新。实测镜像下载 Johnzon 三模块(core 164KB + mapper 264KB + jsonb 150KB,合计约 0.6 MB)数秒完成。

Q3:运行报 NoClassDefFoundError: jakarta/json/Json

运行时 classpath 缺少 jakarta.json-api。使用 shade 打出的 fat-jar(4.6 节已合并全部依赖)运行,或将 jakarta 两个 API jar 一并加入 -cp。

Q4:控制台中文乱码

启动命令加 -Dfile.encoding=UTF-8(或 JAVA_TOOL_OPTIONS 全局设置),并确认 JSON 字符串以 UTF-8 字节读写。

Q5:mvn package 报 invalid target release: 17

构建时实际使用了低版本 JDK。用 mvn -version 核对 Java version 行,必要时 export JAVA_HOME=/opt/java/jdk-17.0.2 后重试。

八、卸载方式

Johnzon 为依赖库,卸载即从工程 pom.xml 删除对应 <dependency>,并清理本地 Maven 仓库缓存:

rm -rf /root/.m2/repository/org/apache/johnzon
rm -rf /root/.m2/repository/jakarta/json
rm -rf /root/.m2/repository/jakarta/json/bind

如采用方案 A 不再需要 JDK/Maven,删除安装目录与软链接:

rm -rf /opt/java/jdk-17.0.2 /opt/maven
rm -f /usr/local/bin/java /usr/local/bin/javac /usr/local/bin/mvn
rm -f /etc/profile.d/javadev.sh

如采用方案 B(apt 安装):

apt-get remove -y openjdk-17-jdk-headless maven

如需删除示例工程目录:

rm -rf /opt/johnzon-demo

九、参考链接