【问题标题】:Path to XML DTD for DBUnit in multi-module Java/Maven project?多模块 Java/Maven 项目中 DBUnit 的 XML DTD 路径?
【发布时间】:2011-03-02 08:41:09
【问题描述】:

我有一个多模块 Maven 项目。在持久模块中,我有许多引用 DTD 的 XML 文件数据文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE myapp-data SYSTEM "myapp-data.dtd" >

<dataset>
      .....omitted for brevity....
</dataset>

DTD 与 XML 文件存储在同一目录中,甚至 Eclipse 也将这些 XML 文件报告为有效。

但是,当我运行应用程序时,DBUnit FlatXMLDataSet 会抛出 FileNotFound 异常,因为它无法定位 DTD。它显然是在根项目目录(例如 myproject/)中寻找 DTD。我原以为它会在与 XML 文件本身相同的目录中查找 DTD(例如 myproject/persist/target/test-data)。

查看 DBUnit 源代码,它有这样的说法“相对 DOCTYPE uri 是从当前工作目录中解析的。”

有什么好的方法可以解决这个问题?

【问题讨论】:

    标签: xml maven-2 dtd dbunit


    【解决方案1】:

    好的,我想我想通了。谢天谢地开源。

    FlatXmlDataSetBuilder 上有一个方法可以将流传输到 DTD。这是一个公共方法 IMO 真是太疯狂了,但话说回来,DBUnit 与 dtd 文件的 XML 不在同一个目录中,这太疯狂了。所以这里是:

    String dtdResourceName = "classpath:test-data/myapp-data.dtd";      
    Resource res = applicationContext.getResource(dtdResourceName);
    builder.setMetaDataSetFromDtd(res.getInputStream());
    

    现在我将带有 dtd 的 DOCTYPE 声明留在与 XML 相同的目录中,并使用此 hack 来欺骗 DBUnit 做正确的事情。

    【讨论】:

    【解决方案2】:

    始终使用正确的变量来访问特殊目录,因为多模块构建与本地构建具有不同的工作目录:

    所以

    • 而不是mydir 使用${project.basedir}/mydir
    • 而不是target/mydir 使用${project.build.directory}/mydir
    • 而不是target/classes/mydir 使用${project.build.outputDirectory}/mydir

    无论从何处调用,这些变量始终计算为当前项目。这是Overview of POM variables(不完整,但最重要的东西在里面)

    此外,如果您想进行一些交互式查询式调试,help:evaluate mojo 会派上用场:

    打电话

    mvn help:evaluate
    

    你会被提示输入一个表达式。如果您输入一个表达式,例如${project.build.plugins[0]} ,将列出指定元素的合并dom


    编辑:

    好的,现在我想我看到了问题所在。那为什么不直接引用xml中的目录:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE myapp-data SYSTEM "target/test-classes/myapp-data.dtd" >
    

    我知道它不漂亮,但它应该可以工作,不管是否是多模块。单元测试的当前目录始终是当前 ${project.basedir},而不是父项目目录。

    【讨论】:

    • 我认为问题不在于 Maven,而在于 DBUnit。它在 DTD 中寻找错误的位置。还有另一种更好的方法来在 XML 文件中指定它吗?是否有我缺少的 DBUnit 设置?
    • 采用新方法可以很好地解决运行时问题——但现在 Eclipse 抱怨它无法找到要验证的 DTD。我也想吃蛋糕!!
    • “目标”目录仅在 maven 构建后存在。如果我运行 mvn clean 它不存在,然后 Eclipse 又开始抱怨了!我检查了 DBUnit 的源代码,他们真的不遗余力地找不到 dtd....
    【解决方案3】:

    您可以将 DTD 发布到 Web 服务器,然后将其 HTTP URL 放入 DOCTYPE,例如:

    <!DOCTYPE myapp-data SYSTEM "-//The Owner//The Description//EN" "http://host/path/to/myapp-data.dtd">
    

    【讨论】:

      【解决方案4】:

      在打开 XML 文件时尝试使用“File”而不是“FileInputStream”。

      例如:

      ReplacementDataSet dataSet = new ReplacementDataSet(new FlatXmlDataSet(new File(fileName)));
      

      这样,DTD 的相对路径应该以 XML 文件的目录开头。

      如果你使用

      ReplacementDataSet dataSet = new ReplacementDataSet(new FlatXmlDataSet(new FileInputStream(fileName)));
      

      路径应该是相对于当前工作目录的。

      【讨论】:

        【解决方案5】:

        这涉及一些难看的重复,但您可以将 DTD 的内容粘贴到相关的 XML 文件中,然后将它们用作internal DTDs

        【讨论】:

          猜你喜欢
          • 2014-02-03
          • 2012-06-20
          • 2010-12-31
          • 2011-02-01
          • 1970-01-01
          • 2018-02-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多