如何避免Jackson XmlMapper序列化Map时转义XML特殊字符?
解决Jackson XmlMapper转义Map值中XML特殊字符的问题
这个问题我之前也碰到过——Jackson默认会把字符串里的<、>这类XML特殊字符转义成实体,因为它默认把字符串当成普通文本处理。要让嵌套的XML内容直接输出不转义,有几种可行的方案,你可以根据自己的场景选择:
方案1:用RawValue包装XML字符串(最简洁)
Jackson提供了RawValue类,专门用来标记需要直接输出、不做转义的内容。你只需要把原来的Map<String, String>转换成Map<String, Object>,将XML字符串包装成RawValue实例即可:
import com.fasterxml.jackson.databind.util.RawValue; // 假设你的原始Map是obj Map<String, Object> rawMap = new HashMap<>(); for (Map.Entry<String, String> entry : obj.entrySet()) { rawMap.put(entry.getKey(), new RawValue(entry.getValue())); } // 执行序列化 String xml = xmlMapper.writer().writeValueAsString(rawMap);
这样Jackson会直接把RawValue中的XML内容输出,不会转义任何特殊字符。
方案2:自定义包装类+@JacksonXmlText注解(更安全,不影响全局)
如果不想改变全局的字符串序列化行为,你可以创建一个专门的包装类,用@JacksonXmlText注解标记内容字段,告诉Jackson这是要直接输出的XML文本:
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText; public class RawXmlContent { @JacksonXmlText private String content; public RawXmlContent(String content) { this.content = content; } // 必须提供getter,Jackson需要访问字段内容 public String getContent() { return content; } public void setContent(String content) { this.content = content; } }
然后将原始Map转换为包装类的Map:
Map<String, RawXmlContent> wrappedMap = new HashMap<>(); for (Map.Entry<String, String> entry : obj.entrySet()) { wrappedMap.put(entry.getKey(), new RawXmlContent(entry.getValue())); } String xml = xmlMapper.writer().writeValueAsString(wrappedMap);
这个方案只会影响被包装的内容,其他字符串的序列化行为保持默认,适合只有部分内容需要不转义的场景。
方案3:自定义全局字符串序列化器(不推荐,影响全局)
如果你希望所有字符串类型的内容都不转义,可以自定义一个序列化器并注册到XmlMapper中:
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.std.StdSerializer; import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator; import java.io.IOException; public class RawXmlStringSerializer extends StdSerializer<String> { public RawXmlStringSerializer() { super(String.class); } @Override public void serialize(String value, JsonGenerator gen, SerializerProvider provider) throws IOException { if (gen instanceof ToXmlGenerator) { // 针对XML生成器,直接写入原始内容 ((ToXmlGenerator) gen).writeRawValue(value); } else { // 非XML场景,回退到默认序列化逻辑 gen.writeString(value); } } }
然后注册这个序列化器:
XmlMapper xmlMapper = new XmlMapper(); SimpleModule module = new SimpleModule(); module.addSerializer(String.class, new RawXmlStringSerializer()); xmlMapper.registerModule(module); String xml = xmlMapper.writer().writeValueAsString(obj);
⚠️ 注意:这个方案会改变所有字符串的序列化行为,如果你的其他字符串需要正常转义(比如包含特殊字符的普通文本),会导致XML格式错误,所以除非你确定所有字符串都是原始XML,否则不建议使用。
内容的提问来源于stack exchange,提问作者Bằng Rikimaru
相关产品推荐
相关产品推荐

