首页 > 解决方案 > 自定义实体导致的 Jackson XML“未声明的一般实体”

问题描述

我正在反序列化一个大型 XML 文件(不是我的),它包含定义为的自定义实体:

<!ENTITY math "mathematics">

和以这种方式使用的元素:

<field>&math;</field>

当我尝试通过以下方式反序列化它时:

XmlMapper xmlMapper = new XmlMapper();
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
return xmlMapper.readValue(classloader.getResourceAsStream("file.xml"), MyClass.class);

我收到此错误:com.fasterxml.jackson.databind.JsonMappingException:未声明的一般实体“数学”

我认为这可能是一种防止 Xml 外部实体注入的安全措施。

  1. 有没有办法将这些自定义实体标记为有效?像为他们创建一个 Enum 之类的?
  2. 如果没有,是否有一个标志可以将它们解析为字符串?

更新:我基本上可以通过对文本文件进行查找替换来解决这个问题。这是一个非常丑陋的解决方案,如果有人有更好的主意,我会全力以赴。:)

标签: jackson-dataformat-xml

解决方案


我知道这可能有点晚了,但以防其他人陷入同样的​​问题:

您必须将自定义 XMLResolver 设置为 XMLInputFactory 的属性:

import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.ctc.wstx.api.WstxInputProperties;
import javax.xml.stream.XMLResolver;
import javax.xml.stream.XMLStreamException;

var xmlMapper = new XmlMapper();
xmlMapper.getFactory().getXMLInputFactory().setProperty(
    WstxInputProperties.P_UNDECLARED_ENTITY_RESOLVER,
    new XMLResolver() {
        @Override
        public Object resolveEntity(String publicId, String systemId, String baseUri, String ns) throws XMLStreamException {
            // replace the entity with a string of your choice, e.g.
            switch (ns) {
                case "nbsp": 
                    return " ";
                default: 
                    return "";
            }
            // some useful tool is org.apache.commons.text.StringEscapeUtils
            // e.g.
            // return StringEscapeUtils.escapeXml10(StringEscapeUtils.unescapeHtml4('&' + ns + ';'));
        }
    }
);

// then xmlMapper.readValue....

推荐阅读