SpringBoot测试中ObjectMapper误将XML当JSON解析,如何正确注入解析器?
问题描述
我在Spring Boot测试里尝试用自定义反序列化器解析XML,测试代码如下:
@SpringBootTest public class MyTest { @Autowired ObjectMapper mapper; @Test public void shouldParseXmlString() { final String input = "<abc>value</abc>"; // 合法的XML字符串 MyClass myClass = mapper.readValue(input, MyClass.class); assertEquals("value", myClass.getAbc()); } }
我有一个继承自JsonDeserializer<MyClass>的自定义反序列化器,用来把XML转成MyClass对象。直接用XmlMapper的时候解析正常,但注入ObjectMapper后执行测试就报错:
com.fasterxml.jackson.core.JsonParseException: Unexpected character ('<' (code 60)) expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')
很明显ObjectMapper把输入的XML字符串当成JSON来解析了。请问怎么通过注入ObjectMapper或者XmlMapper来实现XML解析?我的pom.xml已经加了版本2.10.0的jackson-core和jackson-dataformat-xml依赖。
解决方案
这个问题的核心原因很简单:Spring Boot默认自动配置的ObjectMapper是专门处理JSON格式的,它不会识别XML的语法,所以才会抛出JSON解析错误。这里给你两种可行的解决思路:
方案一:直接注入XmlMapper(推荐)
当你的项目中引入了jackson-dataformat-xml依赖时,Spring Boot会自动配置一个XmlMapper的Bean,你可以直接注入它来处理XML解析,而且它能很好地兼容你的自定义反序列化器。
修改后的测试代码
@SpringBootTest public class MyTest { @Autowired XmlMapper mapper; // 替换成XmlMapper @Test public void shouldParseXmlString() { final String input = "<abc>value</abc>"; MyClass myClass = mapper.readValue(input, MyClass.class); assertEquals("value", myClass.getAbc()); } }
关联自定义反序列化器
如果你的自定义反序列化器是通过@JsonDeserialize注解标注在MyClass上的,比如:
@JsonDeserialize(using = MyCustomDeserializer.class) public class MyClass { private String abc; // getter、setter省略 }
那XmlMapper会自动识别这个注解并应用你的反序列化逻辑,不需要额外配置。
如果需要手动注册反序列化器,可以自定义XmlMapper的Bean:
@Configuration public class JacksonXmlConfig { @Bean public XmlMapper xmlMapper() { XmlMapper xmlMapper = new XmlMapper(); // 注册自定义反序列化器 xmlMapper.registerModule(new SimpleModule() .addDeserializer(MyClass.class, new MyCustomDeserializer())); return xmlMapper; } }
方案二:配置ObjectMapper支持XML格式(不推荐,仅当需要复用ObjectMapper时考虑)
如果你一定要用ObjectMapper来处理XML,可以给它指定XML的底层工厂实现,但这样ObjectMapper会同时处理JSON和XML,可能带来格式识别的冲突,所以更推荐用专门的XmlMapper。
配置示例:
@Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper() { // 使用XmlFactory替换默认的JsonFactory,让ObjectMapper支持XML解析 ObjectMapper objectMapper = new ObjectMapper(new XmlFactory()); // 注册自定义反序列化器 objectMapper.registerModule(new SimpleModule() .addDeserializer(MyClass.class, new MyCustomDeserializer())); return objectMapper; } }
内容的提问来源于stack exchange,提问作者Not a bug

