多模块Java / Maven项目中DBUnit的XML DTD路径?

时间:2020-12-19 23:55:08

I have a multi-module maven project. Within the persist module I have a number of XML files data files that reference a DTD:

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

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

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

The DTD is stored in the same directory with the XML files and even Eclipse reports these XML files as valid.

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

However, when I run the application, the DBUnit FlatXMLDataSet throws a FileNotFound exception because it cannot located the DTD. It is apparently looking for the DTD in the root project directory (e.g. myproject/). I would have expected it to look for the DTD in the same directory as the XML file itself (e.g. myproject/persist/target/test-data).

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

Looking at the DBUnit source code, it has this to say about it "Relative DOCTYPE uri are resolved from the current working dicrectory."

查看DBUnit源代码,可以这样说:“相对DOCTYPE uri是从当前工作的dicrectory中解决的。”

What's a good way to fix this?

有什么好办法解决这个问题?

5 个解决方案

#1


8  

OK, I think I figured this one out. Thank goodness for open source.

好的,我想我想出了这个。谢谢开源。

There is a method on FlatXmlDataSetBuilder that takes a stream to the DTD. It's crazy that this is a public method IMO, but then again, its crazy that DBUnit doesn't look in the same directory as the XML for the dtd file. So here it is:

FlatXmlDataSetBuilder上有一个方法,它将流传递给DTD。这是一个公共方法IMO,这很疯狂,但是再一次,它疯狂的是DBUnit与dtd文件的XML不在同一目录中。所以这里是:

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

Now I leave the DOCTYPE declaration with the dtd in the same directory as the XML and use this hack to fool DBUnit into doing the Right Thing.

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

#2


3  

Always use the correct variables to access special directories, because multi-module builds have a different working directory than local builds:

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

So

所以

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

These variables always evaluate to the current project, no matter where it is called from. Here is an Overview of POM variables (not complete but the most important stuff is in there)

这些变量总是评估当前项目,无论它从哪里调用。这是一个POM变量概述(不完整,但最重要的东西在那里)

Also, if you ever want to do some interactive query-style debugging, the help:evaluate mojo comes in handy:

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

just call

只是打电话

mvn help:evaluate

and you will be prompted for an expression. If you enter an expression e.g. ${project.build.plugins[0]} , the merged dom for the specified element will be listed

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


EDIT:

编辑:

ok, now I think I see the problem. then why not just reference the directory in the xml:

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

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

I know it's not pretty, but it should work, multi-module or not. the current directory for unit tests is always the current ${project.basedir}, not the parent project dir.

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

#3


1  

You could publish the DTD to a web server and then put its HTTP URL into the DOCTYPE, e.g.:

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

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

#4


0  

Try using "File" instead of "FileInputStream" when opening an XML file.

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

For example:

例如:

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

This way, relative path to DTD should start with directory of the XML file.

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

And if you use

如果你使用

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

path should be relative to current working directory.

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

#5


0  

It involves some ugly duplication, but you could paste the contents of the DTD into the XML file(s) in question and then use them as internal DTDs.

它涉及一些丑陋的重复,但您可以将DTD的内容粘贴到相关的XML文件中,然后将它们用作内部DTD。

#1


8  

OK, I think I figured this one out. Thank goodness for open source.

好的,我想我想出了这个。谢谢开源。

There is a method on FlatXmlDataSetBuilder that takes a stream to the DTD. It's crazy that this is a public method IMO, but then again, its crazy that DBUnit doesn't look in the same directory as the XML for the dtd file. So here it is:

FlatXmlDataSetBuilder上有一个方法,它将流传递给DTD。这是一个公共方法IMO,这很疯狂,但是再一次,它疯狂的是DBUnit与dtd文件的XML不在同一目录中。所以这里是:

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

Now I leave the DOCTYPE declaration with the dtd in the same directory as the XML and use this hack to fool DBUnit into doing the Right Thing.

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

#2


3  

Always use the correct variables to access special directories, because multi-module builds have a different working directory than local builds:

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

So

所以

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

These variables always evaluate to the current project, no matter where it is called from. Here is an Overview of POM variables (not complete but the most important stuff is in there)

这些变量总是评估当前项目,无论它从哪里调用。这是一个POM变量概述(不完整,但最重要的东西在那里)

Also, if you ever want to do some interactive query-style debugging, the help:evaluate mojo comes in handy:

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

just call

只是打电话

mvn help:evaluate

and you will be prompted for an expression. If you enter an expression e.g. ${project.build.plugins[0]} , the merged dom for the specified element will be listed

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


EDIT:

编辑:

ok, now I think I see the problem. then why not just reference the directory in the xml:

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

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

I know it's not pretty, but it should work, multi-module or not. the current directory for unit tests is always the current ${project.basedir}, not the parent project dir.

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

#3


1  

You could publish the DTD to a web server and then put its HTTP URL into the DOCTYPE, e.g.:

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

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

#4


0  

Try using "File" instead of "FileInputStream" when opening an XML file.

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

For example:

例如:

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

This way, relative path to DTD should start with directory of the XML file.

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

And if you use

如果你使用

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

path should be relative to current working directory.

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

#5


0  

It involves some ugly duplication, but you could paste the contents of the DTD into the XML file(s) in question and then use them as internal DTDs.

它涉及一些丑陋的重复,但您可以将DTD的内容粘贴到相关的XML文件中,然后将它们用作内部DTD。