2

我遇到了很多 JAXB 序列化错误,这些错误是由于代码在各个地方创建了无效的限定名称这一事实引起的。我正在研究我正在使用的 API 和其他 java XML 选项,奇怪的是实现限定名称的类似乎根本不做任何输入检查。

这确实是有问题的,因为复杂的代码会生成各种 JAXB 对象,并且直到编组时间才发现某些东西出了严重的错误。异常堆栈通常不会告诉您哪个元素/属性是错误的,只是有问题。

这些库一开始就让创建不可序列化的内容变得更加困难,难道不​​是更有意义吗?

这是一个代码片段:为什么会这样?它不应该抛出一个IllegalArgumentException吗?在其他定义 QName 的 API 中,行为是相同的。此类的 javadocs 指定如果命名空间为空,您将得到一个IllegalArgumentException,否则不会。

    QName q = new QName("Namespace URI is supposed to be an anyURI, but clearly !!THIS ISN'T!!", 
                        "Local part is supposed to be an NCName, but clearly !!THIS ISN'T!!",
                        "<><><><>&&& Laughably Invalid Namespace Prefix");
    System.out.println(q);

参考: QName 的相关 javadoc说明 name 是 anyURI 的规范约束,而 localpart 是 NCName。换句话说,根据规范,上面的代码显然是无效的,与序列化无关。

4

2 回答 2

2

假设在这里。

QName 构造函数的主要用户很可能不是通用 Java 代码本身,而是 XML 解析器。

XML 解析对性能很敏感。如果解析器正在调用构造函数,理论上解析器已经验证了语法,所以再次验证它是浪费时间。

这是一个 95% 的问题。为什么要为 5% 的用户付出代价。

如果您想要一个验证 QName 构造函数,您可以扩展 QName 并添加您自己的代码。

例如:

public class VerifiedQName extends QName {
    public VerifiedQName(String namespaceURI, String localPart) {            
        super(namespaceURI, localPart);
        verfiyNamespaceURI(namespaceURI); // throws IllegalArgumentException
        verifyLocalPart(localPart);  // throws IllegalArgumentException
    }
    ...
}

至少该类被记录为未验证。

于 2014-04-28T14:29:46.823 回答
1

javax.xml.namespace.QName不是 JAXB 类,它只是 JAXB 利用的 Java SE 的一部分。

不验证数据的原因

  1. String操作成本高,您想每次都接受检查String吗?
  2. 如果有效的本地名称或命名空间的定义发生了变化,那么您是否需要告知QName要针对哪个版本的定义进行验证?在 Java SE 中的版本更新以支持它之前,您是否无法利用新定义?
  3. 在紧要关头,您可以将它与非 XML 数据一起使用。一些 JAXB 实现(即 MOXy)支持 XML(即 JSON)以外的格式,具有诸如QName容忍“无效”数据之类的类允许它们以不同于预期的方式使用。

更新

你知道这些是原因,还是你在猜测?

纯属猜测,但我确实领导了JAXB 的EclipseLink MOXy实现。

为什么字符串检查在构造函数中会很昂贵?

比什么都不做要贵。此外,即使每次构造函数调用的成本很小,执行足够的操作也会变得昂贵。

值得一提的是,与规范相关的其他类型(如 URL 和 URI)都会从其构造函数中抛出无效格式的异常。

您通常不会创建很多这些对象,因此异常中的用户帮助超过了进行检查的成本。

另外,QNames 的定义什么时候改变?

诚然,它不太可能改变。然而,如今 JAXB 实现通常用于支持的不仅仅是 XML。QName当您从另一种格式(例如 JSON)读取/写入数据时,具有容错性的实现非常方便。

于 2014-04-28T14:13:12.903 回答