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)依赖,编译打包并运行真实示例程序的全流程集成指南。
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-core | 2.2.0 | Jakarta JSON Processing 实现(解析/生成/指针) |
| Mapper | org.apache.johnzon : johnzon-mapper | 2.2.0 | POJO ↔ JSON 对象映射引擎 |
| JSON-B | org.apache.johnzon : johnzon-jsonb | 2.2.0 | Jakarta JSON Binding 实现(含 JAX-RS Provider) |
| JSON-P API | jakarta.json : jakarta.json-api | 2.1.3 | JSON Processing API(Johnzon 声明为 provided,须显式引入) |
| JSON-B API | jakarta.json.bind : jakarta.json.bind-api | 3.0.1 | JSON 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
九、参考链接
- Apache Johnzon 官网:https://johnzon.apache.org/
- Johnzon Maven 仓库(版本查询):https://repo.maven.apache.org/maven2/org/apache/johnzon/johnzon-core/
- Jakarta JSON Processing 规范:https://jakarta.ee/specifications/jsonp/2.1/
- Jakarta JSON Binding 规范:https://jakarta.ee/specifications/jsonb/3.0/
- 华为云开源镜像站(OpenJDK/Maven 二进制):https://mirrors.huaweicloud.com/
- 阿里云 Maven 镜像:https://developer.aliyun.com/mirror/maven