轻量实用的 XML 与 JSON / 对象互转工具类(Jackson 实现)

轻量实用的XML与JSON/对象互转工具类(Jackson实现)

在日常开发中,XML与JSON、Java对象之间的转换是高频需求,比如接口对接、数据解析等场景。本文将分享一个基于Jackson框架实现的轻量工具类,支持多输入源、无日志依赖、兼容JDK8+,同时解决了版本兼容和异常处理等常见问题,适合作为基础工具嵌入各类项目。

一、工具类核心特性

  • 无日志依赖:纯基础工具实现,不引入额外日志框架,轻量无冗余
  • 功能全面:支持XML字符串/文件/输入流与JSON、Java对象的双向转换
  • 灵活配置:支持JSON格式化输出开关,兼容JDK8 LocalDateTime等日期类型
  • 版本兼容:解决Jackson不同版本间的特性差异(如WRITE_XML_DECLARATION常量兼容)
  • 异常友好:自定义转换异常,错误信息清晰,便于问题定位
  • 线程安全:Jackson映射器采用静态单例模式,线程安全且性能优异

二、完整工具类实现

java 复制代码
package com.dolphin.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * XML与JSON/对象互转工具类
 * 支持XML字符串/文件/输入流与JSON、Java对象之间的双向转换
 * 无日志依赖、兼容JDK8+、线程安全、版本兼容
 *
 * @author: DolphinHome
 * @date: 2025/10/31 1:23
 */
public class XmlToJsonUtils {
    
    // XML处理映射器(线程安全,单例模式)
    private static final XmlMapper xmlMapper;
    
    // JSON处理映射器(线程安全,单例模式)
    private static final ObjectMapper jsonMapper;

    static {
        // 初始化XML映射器并配置核心特性
        xmlMapper = new XmlMapper();
        configureXmlMapper(xmlMapper);
        
        // 初始化JSON映射器并配置核心特性
        jsonMapper = new ObjectMapper();
        configureJsonMapper(jsonMapper);
    }

    /**
     * 配置XML映射器核心特性
     */
    private static void configureXmlMapper(XmlMapper mapper) {
        // 忽略未知属性,提高转换容错性
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 注册JDK8日期时间模块,支持LocalDateTime/LocalDate等类型
        mapper.registerModule(new JavaTimeModule());
        // 允许空Bean序列化,避免无字段类转换失败
        mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        
        // 兼容不同Jackson版本:尝试设置XML声明忽略(无则忽略)
        try {
            SerializationFeature feature = SerializationFeature.valueOf("WRITE_XML_DECLARATION");
            mapper.configure(feature, false);
        } catch (IllegalArgumentException e) {
            // 低版本Jackson不支持该特性,直接忽略
        }
    }

    /**
     * 配置JSON映射器核心特性
     */
    private static void configureJsonMapper(ObjectMapper mapper) {
        // 忽略未知属性,避免JSON字段与对象不匹配时失败
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 支持JDK8日期时间类型序列化/反序列化
        mapper.registerModule(new JavaTimeModule());
        // 默认开启JSON格式化输出(可通过参数关闭)
        mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
        // 日期时间以ISO格式输出(如2025-10-31T10:00:00),而非时间戳
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    }

    // ------------------------------ XML转JSON核心方法 ------------------------------

    /**
     * XML字符串转JSON字符串(默认格式化输出)
     * @param xml 待转换的XML字符串
     * @return 格式化后的JSON字符串
     * @throws ConversionException 转换失败时抛出
     */
    public static String xmlToJson(String xml) {
        return xmlToJson(xml, true);
    }

    /**
     * XML字符串转JSON字符串(支持格式化开关)
     * @param xml 待转换的XML字符串
     * @param prettyPrint 是否格式化输出(true=带缩进,false=紧凑格式)
     * @return 转换后的JSON字符串
     * @throws ConversionException 转换失败时抛出
     */
    public static String xmlToJson(String xml, boolean prettyPrint) {
        validateXmlInput(xml);
        
        try {
            JsonNode jsonNode = xmlMapper.readTree(xml);
            return prettyPrint ? 
                   jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonNode) :
                   jsonMapper.writeValueAsString(jsonNode);
        } catch (JsonProcessingException e) {
            throw new ConversionException("XML转JSON失败: " + e.getMessage(), e);
        }
    }

    /**
     * XML文件转JSON字符串(默认格式化输出)
     * @param filePath XML文件绝对路径
     * @return 格式化后的JSON字符串
     * @throws ConversionException 文件读取或转换失败时抛出
     */
    public static String xmlFileToJson(String filePath) {
        return xmlFileToJson(filePath, true);
    }

    /**
     * XML文件转JSON字符串(支持格式化开关)
     * @param filePath XML文件绝对路径
     * @param prettyPrint 是否格式化输出
     * @return 转换后的JSON字符串
     * @throws ConversionException 文件读取或转换失败时抛出
     */
    public static String xmlFileToJson(String filePath, boolean prettyPrint) {
        try {
            // 以UTF-8编码读取文件内容
            String xmlContent = new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8);
            return xmlToJson(xmlContent, prettyPrint);
        } catch (IOException e) {
            throw new ConversionException("读取XML文件或转换JSON失败: " + e.getMessage(), e);
        }
    }

    /**
     * 输入流XML转JSON字符串(默认格式化输出)
     * @param inputStream 包含XML内容的输入流(如HTTP请求流、文件流)
     * @return 格式化后的JSON字符串
     * @throws ConversionException 流读取或转换失败时抛出
     */
    public static String xmlStreamToJson(InputStream inputStream) {
        return xmlStreamToJson(inputStream, true);
    }

    /**
     * 输入流XML转JSON字符串(支持格式化开关)
     * @param inputStream 包含XML内容的输入流
     * @param prettyPrint 是否格式化输出
     * @return 转换后的JSON字符串
     * @throws ConversionException 流读取或转换失败时抛出
     */
    public static String xmlStreamToJson(InputStream inputStream, boolean prettyPrint) {
        if (inputStream == null) {
            throw new ConversionException("输入流不能为null");
        }

        try {
            JsonNode jsonNode = xmlMapper.readTree(inputStream);
            return prettyPrint ? 
                   jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonNode) :
                   jsonMapper.writeValueAsString(jsonNode);
        } catch (IOException e) {
            throw new ConversionException("从输入流转换XML到JSON失败: " + e.getMessage(), e);
        }
    }

    // ------------------------------ XML转Java对象核心方法 ------------------------------

    /**
     * XML字符串直接转Java对象
     * @param xml 待转换的XML字符串
     * @param clazz 目标对象的Class类型
     * @param <T> 目标对象泛型
     * @return 转换后的Java对象
     * @throws ConversionException 转换失败时抛出
     */
    public static <T> T xmlToObject(String xml, Class<T> clazz) {
        validateXmlInput(xml);
        
        try {
            return xmlMapper.readValue(xml, clazz);
        } catch (JsonProcessingException e) {
            throw new ConversionException("XML转" + clazz.getSimpleName() + "失败: " + e.getMessage(), e);
        }
    }

    /**
     * XML文件直接转Java对象
     * @param filePath XML文件绝对路径
     * @param clazz 目标对象的Class类型
     * @param <T> 目标对象泛型
     * @return 转换后的Java对象
     * @throws ConversionException 文件读取或转换失败时抛出
     */
    public static <T> T xmlFileToObject(String filePath, Class<T> clazz) {
        try {
            return xmlMapper.readValue(new File(filePath), clazz);
        } catch (IOException e) {
            throw new ConversionException("XML文件转" + clazz.getSimpleName() + "失败: " + e.getMessage(), e);
        }
    }

    // ------------------------------ 输入验证辅助方法 ------------------------------

    /**
     * 验证XML字符串输入合法性
     * @param xml 待验证的XML字符串
     * @throws ConversionException 输入为null或空字符串时抛出
     */
    private static void validateXmlInput(String xml) {
        if (xml == null || xml.trim().isEmpty()) {
            throw new ConversionException("XML字符串不能为null或空");
        }
    }

    // ------------------------------ 自定义转换异常 ------------------------------

    /**
     * 转换异常封装类:统一捕获转换过程中的所有异常
     */
    public static class ConversionException extends RuntimeException {
        public ConversionException(String message) {
            super(message);
        }

        public ConversionException(String message, Throwable cause) {
            super(message, cause);
        }
    }
}

三、Maven依赖配置

工具类基于Jackson框架实现,需引入以下依赖(JDK8+适用),注意所有Jackson模块版本必须一致

xml 复制代码
<properties>
    <!-- 统一Jackson版本(建议2.15+,兼容JDK8+且修复较多漏洞) -->
    <jackson.version>2.17.1</jackson.version>
</properties>

<dependencies>
    <!-- Jackson核心模块:JSON解析/生成基础 -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>${jackson.version}</version>
    </dependency>

    <!-- Jackson注解模块:支持@JsonProperty等注解(databind依赖) -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>${jackson.version}</version>
    </dependency>

    <!-- Jackson对象绑定模块:核心功能(对象↔JSON) -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>${jackson.version}</version>
    </dependency>

    <!-- JDK8日期时间支持模块:必须引入,否则LocalDateTime等类型转换失败 -->
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
        <version>${jackson.version}</version>
    </dependency>

    <!-- Jackson XML支持模块:XML解析核心依赖 -->
    <dependency>
        <groupId>com.fasterxml.jackson.dataformat</groupId>
        <artifactId>jackson-dataformat-xml</artifactId>
        <version>${jackson.version}</version>
    </dependency>
</dependencies>

依赖说明:

  1. 若项目已引入spring-boot-starter-web,Spring Boot会自动依赖Jackson核心模块,此时只需指定jackson.version即可,无需重复引入
  2. 版本必须统一:不同版本的Jackson模块混合使用会导致类缺失、方法不兼容等问题
  3. jackson-datatype-jsr310模块是JDK8+必备,否则LocalDateTime、LocalDate等类型无法正常序列化/反序列化

四、快速使用示例

1. XML字符串转JSON

java 复制代码
public class TestXmlToJson {
    public static void main(String[] args) {
        // 待转换的XML字符串
        String xml = "<user>" +
                        "<id>1001</id>" +
                        "<name>张三</name>" +
                        "<age>25</age>" +
                        "<createTime>2025-10-31T09:30:00</createTime>" +
                     "</user>";
        
        try {
            // 默认格式化输出JSON
            String json = XmlToJsonUtils.xmlToJson(xml);
            System.out.println("格式化JSON:" + json);
            
            // 紧凑格式输出JSON(无缩进)
            String compactJson = XmlToJsonUtils.xmlToJson(xml, false);
            System.out.println("紧凑JSON:" + compactJson);
        } catch (XmlToJsonUtils.ConversionException e) {
            // 异常处理(如日志记录、友好提示)
            e.printStackTrace();
        }
    }
}

2. XML文件转Java对象

假设存在user.xml文件,内容同上,且有对应的Java实体类:

java 复制代码
// Java实体类
public class User {
    private Long id;
    private String name;
    private Integer age;
    private LocalDateTime createTime;

    // getter/setter省略
}

// 转换测试
public class TestXmlToObject {
    public static void main(String[] args) {
        try {
            // XML文件路径(绝对路径)
            String filePath = "D:/data/user.xml";
            // 直接转换为User对象
            User user = XmlToJsonUtils.xmlFileToObject(filePath, User.class);
            System.out.println("用户ID:" + user.getId());
            System.out.println("创建时间:" + user.getCreateTime());
        } catch (XmlToJsonUtils.ConversionException e) {
            e.printStackTrace();
        }
    }
}

3. 输入流XML转JSON(如HTTP请求)

java 复制代码
// 模拟HTTP请求获取XML输入流(实际场景可替换为真实请求流)
InputStream inputStream = new FileInputStream("D:/data/user.xml");

try {
    String json = XmlToJsonUtils.xmlStreamToJson(inputStream);
    System.out.println("输入流转换结果:" + json);
} catch (FileNotFoundException | XmlToJsonUtils.ConversionException e) {
    e.printStackTrace();
} finally {
    // 关闭输入流(实际开发中建议用try-with-resources)
    inputStream.close();
}

五、注意事项

  1. 编码规范:工具类默认使用UTF-8编码读取文件和转换,若XML文件为其他编码(如GBK),需手动指定编码格式
  2. 线程安全:XmlMapper和ObjectMapper是线程安全的,无需每次转换都创建实例,工具类已通过静态单例优化
  3. 异常处理:所有转换异常都会封装为ConversionException,上层调用时可统一捕获处理,无需关注底层具体异常
  4. 复杂XML支持:支持包含子节点、列表的复杂XML结构,转换后的JSON会保持对应的层级关系
  5. 空值处理:XML中的空标签会转换为JSON的null值,Java对象中的空字段也会正常序列化

六、总结

这个工具类基于Jackson实现,兼顾了轻量性和实用性,移除了日志依赖,适合作为基础组件嵌入各类Java项目。它解决了日常开发中XML与JSON、Java对象转换的核心需求,同时处理了版本兼容、异常封装、输入验证等细节问题,让开发者无需关注底层实现,直接调用静态方法即可完成转换。

如果需要扩展功能(如JSON转XML、支持更多输入源),可以基于现有代码轻松扩展。工具类的方法命名规范、注释清晰,上手成本极低,推荐在实际项目中使用。

相关推荐
雨中飘荡的记忆34 分钟前
Java + Groovy计费引擎详解
java·groovy
嘟嘟w34 分钟前
JVM(Java 虚拟机):核心原理、内存模型与调优实践
java·开发语言·jvm
合作小小程序员小小店34 分钟前
web开发,在线%药店管理%系统,基于Idea,html,css,jQuery,java,ssm,mysql。
java·前端·mysql·jdk·html·intellij-idea
ZHE|张恒36 分钟前
设计模式(八)组合模式 — 以树结构统一管理对象层级
java·设计模式·组合模式
TDengine (老段)38 分钟前
TDengine 转换函数 CAST 用户手册
java·大数据·数据库·物联网·时序数据库·tdengine·涛思数据
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ42 分钟前
java实现校验sql中,表字段在表里是否都存在,不存在的给删除掉
java·sql
编程火箭车1 小时前
【Java SE 基础学习打卡】15 分隔符、标识符与关键字
java·java入门·标识符·关键字·编程基础·分隔符·语法规则
灰色人生qwer1 小时前
idea teminal和 window cmd 输出java version不一致
java·ide·intellij-idea
WayneJoon.H1 小时前
Java反序列化 CC7链分析
java·安全·网络安全·cc链·反序列化
liu_bees2 小时前
Jenkins 中修改 admin 账号密码的正确位置与方法
java·运维·tomcat·jenkins