
在使用jackson objectmapper 进行json反序列化时,如果尝试将一个空的 byte[] 或 inputstream 反序列化为java对象,通常会遇到 com.fasterxml.jackson.databind.exc.mismatchedinputexception: no content to map due to end-of-input 异常。例如:
ObjectMapper objectMapper = new ObjectMapper();
byte[] val = new byte[] {}; // 空字节数组
// objectMapper.readValue(val, new TypeReference<Object>() {}); // 会抛出 MismatchedInputException尽管Jackson提供了 DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT 等配置项,但这些特性主要用于处理空JSON数组 [],而不是完全没有内容的输入流或字节数组。对于后者,ObjectMapper 在尝试读取任何内容之前就发现输入结束,因此无法映射。
在实际应用中,我们可能无法控制输入数据的来源,需要一种健壮的方式来处理这种空输入,使其不抛出异常,而是返回 null 或一个空的 Optional。
解决此问题的核心思路是,在将数据直接交给 ObjectMapper 进行类型映射之前,先使用Jackson的低级流式API JsonParser 对输入内容进行初步检查。如果 JsonParser 发现没有内容可解析,我们就可以提前判断并返回 null,避免 ObjectMapper 抛出异常。
具体步骤如下:
为了更好地封装这一逻辑,我们可以创建一个泛型工具方法,使其能够处理不同类型的POJO。
首先,我们定义一个用于反序列化的简单Java对象(Plain Old Java Object):
import java.util.Objects;
public class MyPojo {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "MyPojo(name=" + name + ")";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyPojo myPojo = (MyPojo) o;
return Objects.equals(name, myPojo.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}接下来,我们创建 convertBytes 方法,它接收字节数组、目标POJO的Class类型和 ObjectMapper 实例,并返回一个 Optional<T>,以优雅地处理可能为空的结果。
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
public class JacksonEmptyInputHandler {
/**
* 将字节数组反序列化为指定类型的对象,支持处理空字节数组。
* 如果字节数组为空或解析后得到空节点,则返回 Optional.empty()。
*
* @param arr 待反序列化的字节数组
* @param pojoClass 目标POJO的Class类型
* @param mapper ObjectMapper实例
* @param <T> 目标POJO的类型
* @return 包含反序列化对象的Optional,如果输入为空则返回Optional.empty()
* @throws IOException 如果反序列化过程中发生IO异常
*/
public static <T> Optional<T> convertBytes(byte[] arr,
Class<T> pojoClass,
ObjectMapper mapper) throws IOException {
// 通过ObjectMapper的工厂创建JsonParser
JsonParser parser = mapper.getFactory().createParser(arr);
// 使用parser将输入解析为JsonNode
// 如果输入为空,readValueAsTree() 将返回 null
JsonNode node = parser.readValueAsTree();
// 检查解析得到的JsonNode是否为null
if (node != null) {
// 如果JsonNode不为null,说明有内容,将其转换为目标POJO
return Optional.of(mapper.treeToValue(node, pojoClass));
} else {
// 如果JsonNode为null,表示输入为空,返回Optional.empty()
return Optional.empty();
}
}
// 主方法用于测试
public static void main(String[] args) throws IOException {
// 示例JSON字符串
String source = """
{
"name" : "Alice"
}
""";
// 两种输入情况:空字节数组和有效JSON字节数组
byte[] jsonBytesEmpty = {}; // 空字节数组
byte[] jsonBytesValid = source.getBytes(StandardCharsets.UTF_8); // 有效JSON字节数组
ObjectMapper mapper = new ObjectMapper();
// 测试空字节数组
System.out.println("处理空字节数组: " + convertBytes(jsonBytesEmpty, MyPojo.class, mapper));
// 测试有效JSON字节数组
System.out.println("处理有效JSON字节数组: " + convertBytes(jsonBytesValid, MyPojo.class, mapper));
}
}执行上述 main 方法,将得到如下输出:
处理空字节数组: Optional.empty 处理有效JSON字节数组: Optional[MyPojo(name=Alice)]
从输出可以看出,当输入为空字节数组时,convertBytes 方法成功返回了 Optional.empty(),而没有抛出 MismatchedInputException。当输入为有效JSON时,则成功反序列化并返回包含POJO的 Optional。
通过利用Jackson的 JsonParser 和 JsonNode API,我们能够有效地处理 ObjectMapper 在反序列化空字节数组或输入流时抛出的 MismatchedInputException。这种方法通过在解析之前进行内容检查,提供了一种健壮且优雅的方式来避免异常,并结合 Optional 类型提高了代码的健壮性和可读性,确保了应用程序能够平稳地处理各种输入情况。
以上就是Jackson处理空字节数组或流的优雅之道的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号