轻量实用的 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、支持更多输入源),可以基于现有代码轻松扩展。工具类的方法命名规范、注释清晰,上手成本极低,推荐在实际项目中使用。

相关推荐
Yeniden4 小时前
【设计模式】# 外观模式(Facade)大白话讲解!
java·设计模式·外观模式
脚踏实地的大梦想家4 小时前
【Go】P17 Go语言并发编程核心:深入理解 Goroutine (从入门到实战)
java·开发语言·golang
Yeniden4 小时前
【设计模式】 组合模式(Composite)大白话讲解
java·设计模式·组合模式
初学小白...4 小时前
线程同步机制及三大不安全案例
java·开发语言·jvm
CS Beginner5 小时前
【搭建】个人博客网站的搭建
java·前端·学习·servlet·log4j·mybatis
JavaTree20175 小时前
【Spring Boot】Spring Boot解决循环依赖
java·spring boot·后端
lang201509286 小时前
Maven 五分钟入门
java·maven
cj6341181506 小时前
SpringBoot配置Redis
java·后端
用坏多个鼠标6 小时前
Nacos和Nginx集群,项目启动失败问题
java·开发语言