编译依赖于多个模块的模块时,Maven Jaxb生成失败

时间:2013-08-10 15:49:00

标签: maven jaxb build-error xmlcatalog jaxb-episode

我有一个由多个模块组成的Eclipse Maven项目,其中一些模块包含我想为(使用Jaxb)生成类的Xml模式。我的项目布局如下:

schemas\core (pom)
schemas\core\types (jar)
schemas\vehicle (pom)
schemas\vehicle\automobile (jar)
schemas\vehicle\civic (jar)

包含架构的项目是:

schemas\core\types (xsd\types.xsd)
schemas\vehicle\automobile (xsd\automobile.xsd)
schemas\vehicle\civic (xsd\civic.xsd)

某些模块包含从其他模块导入模式的模式:

automobile.xsd imports types.xsd
civic.xsd imports types.xsd, automobile.xsd

由于模式位于不同的项目中,因此我使用类路径目录解析器和目录文件来解析模式的位置。

cars 项目依赖于 types 项目中的模式。以下是其目录文件( catalog.xml )中的条目:

<rewriteSystem systemIdStartString="http://schemas/core/types/" rewritePrefix="classpath:xsd/" />

请注意使用 classpath:xsd / 告诉目录解析程序在类路径中查找模式。

我还使用剧集来防止在 cars 项目中重新生成 types 中的类。这是来自 pom.xml 的snippit:

<plugin>
    <groupId>org.jvnet.jaxb2.maven2</groupId>
    <artifactId>maven-jaxb2-plugin</artifactId>
    <version>0.8.3</version>
    <configuration>
        <episodes>
            <episode>
                <groupId>schemas.core</groupId>
                <artifactId>types</artifactId>
                <version>1.0-SNAPSHOT</version>
            </episode>
        <episodes>
        <catalog>src/main/resources/catalog.xml</catalog>
        <catalogResolver>org.jvnet.jaxb2.maven2.resolver.tools.ClasspathCatalogResolver</catalogResolver>
        <extension>true</extension>
        ....

当我在汽车项目上运行 mvn clean install 时,一切正常。在类路径上解析模式 types.xsd ,最终生成类。

我遇到问题的地方是尝试编译项目 civic

civic 项目取决于 types.xsd automobile.xsd 。我使用目录文件( catalog.xml )来定义模式的位置:

<rewriteSystem systemIdStartString="http://schemas/core/types/" rewritePrefix="classpath:xsd/" />
<rewriteSystem systemIdStartString="http://schemas/vehicle/automobile/" rewritePrefix="classpath:xsd/" />

我使用剧集来防止重新生成类。以下是来自 pom.xml civic 的snippit:

<plugin>
    <groupId>org.jvnet.jaxb2.maven2</groupId>
    <artifactId>maven-jaxb2-plugin</artifactId>
    <version>0.8.3</version>
    <configuration>
        <episodes>
            <episode>
                <groupId>schemas.core</groupId>
                <artifactId>types</artifactId>
                <version>1.0-SNAPSHOT</version>
            </episode>
            <episode>
                <groupId>schemas.vehicle</groupId>
                <artifactId>automobile</artifactId>
                <version>1.0-SNAPSHOT</version>
            </episode>
        </episodes>
        <catalog>src/main/resources/catalog.xml</catalog>
        <catalogResolver>org.jvnet.jaxb2.maven2.resolver.tools.ClasspathCatalogResolver</catalogResolver>
        <extension>true</extension>
        ...

当我尝试在 civic 项目上运行 mvn clean install 时,我遇到了问题。它抱怨无法解决公共/系统ID。以下是我收到的一些错误消息:

Could not resolve publicId [null], systemId [jar:file:/_m2repository/schemas/vehicle/automobile/1.0-SNAPSHOT/automobile-1.0-SNAPSHOT.jar!http://schemas/core/types/types.xsd]
[ERROR] Error while parsing schema(s).Location [].
com.sun.istack.SAXParseException2; 
IOException thrown when processing "jar:file:/_m2repository/schemas/vehicle/automobile/1.0-SNAPSHOT/automobile-1.0-SNAPSHOT.jar!http://schemas/core/types/types.xsd".
Exception: java.net.MalformedURLException: no !/ in spec.
....

由于某些原因,在尝试从汽车项目中解析jar文件时,找不到 types.xsd

有谁知道为什么会这样?

谢谢。

注意 - 我正在尝试打算让事情发挥作用,我确实找到了一种方法。如果我从 pom.xml 文件中删除剧集我不再收到错误,但是,项目 civic 最终会使用依赖模块中的所有类型(这是我想通过使用剧集来避免的事情。

civic project generated java classes

如果您想查看每个项目的完整 catalog.xml pom.xml 文件,请参阅以下链接:

类型:http://pastebin.com/Uym3DY6X

汽车:http://pastebin.com/VQM4MPuW

civic:http://pastebin.com/eGSVGwmE

3 个答案:

答案 0 :(得分:2)

此处maven-jaxb2-plugin的作者。

我只有0.10.0maven-jaxb2-plugin maven-jaxb2-plugin版。此版本修复了与报告的问题相关的released问题。

这实际上不是maven-jaxb2-plugin中的错误,而是XJC本身的一个问题(或者更好地说几个问题):

当目录和绑定文件一起使用时,这些问题会导致问题。这也是Maven工件解决在某些情况下无法正常工作的原因。

在0.10.0版本中,我已经为JAXB-1044和JAXB-1045实现了变通方法。我会尝试通过拉取请求将补丁发送到XJC,但是你知道,我不确定,Oracle的人是否会接受我的PR。

REWRITE_SYSTEM "http://www.ab.org" "maven:org.jvnet.jaxb2.maven2:maven-jaxb2-plugin-tests-MAVEN_JAXB2_PLUGIN-82-a:jar::!" 我现在已经实施了非常可靠的解决方法。请在此处查看此测试项目:

https://java.net/jira/browse/JAXB-1046

这正是您想要的:通过目录和Maven解析器将模式解析为来自另一个工件的资源。基本上,这改写:

mvn -X

现在工作正常。

如果出现问题 <schemas> <schema> <url>http://www.w3.org/1999/xlink.xsd</url> </schema> </schemas> <schemaIncludes/> <bindings> <binding> <dependencyResource> <groupId>${project.groupId}</groupId> <artifactId>w3c-schemas</artifactId> <resource>globalBindings.xjb</resource> <version>${project.version}</version> </dependencyResource> </binding> </bindings> <catalogs> <catalog> <dependencyResource> <groupId>${project.groupId}</groupId> <artifactId>w3c-schemas</artifactId> <resource>catalog.cat</resource> <version>${project.version}</version> </dependencyResource> </catalog> </catalogs> 并检查输出,您还会在日志中看到目录解析器的语句。这可能会给你提示,什么不起作用。

这是另一个项目,它使用模式,绑定和目录本身来自一个中心工件:

https://github.com/highsource/maven-jaxb2-plugin/tree/master/tests/MAVEN_JAXB2_PLUGIN-82

来自POM的片段:

REWRITE_SYSTEM "http://www.w3.org" "maven:org.hisrc.w3c:w3c-schemas:jar::!/w3c"

目录:

<jaxb:bindings schemaLocation="http://www.w3.org/1999/xlink.xsd" node="/xs:schema">
    <jaxb:schemaBindings>
        <jaxb:package name="org.hisrc.w3c.xlink.v_1_0"/>
    </jaxb:schemaBindings>
</jaxb:bindings>

结合:

w3c-schemas

所以这一切是如何运作的:

  • 架构以及目录和全局绑定存储在中央工件http://www.w3.org/1999/xlink.xsd中。
  • 项目想要编译网址maven:org.hisrc.w3c:w3c-schemas:jar::!/w3c/1999/xlink.xsd
  • 目录将此URL重写为systemId /w3c/1999/xlink.xsd。 (w3c-schemas jar中有maven-jaxb2-plugin个资源。
  • 然后将此systemId解析为我的Maven目录解析器(将我的jar:...传递到)“真实”网址,该网址将是w3c-schemas指向dependencyResource内资源的{{1}}网址本地存储库中的工件JAR。
  • 因此,架构不会从Internet下载,而是从本地资源中获取。
  • 解决方法保留“原始”systemIds,因此您可以使用其原始URL自定义架构。 (已解析的systemId将不方便。)
  • 目录文件和全局绑定文件对于所有单个项目都是相同的,因此它们也被放入中央工件并使用{{1}}在那里引用。

答案 1 :(得分:0)

我有同样的问题。模式C导入B和A,B导入A.为A,works,B生成源也很好,对于C,弹出MalformedUrlException。

我仍在调查错误,但解决方法是使用systemIdSuffix(Oasis规范1.1)来匹配systemId并重写它。您需要执行以下操作:

从poms中的插件配置中删除'catalogResolver'元素。

使用以下内容替换“汽车”项目的目录文件的内容:

<systemSuffix systemIdSuffix="types.xsd" uri="maven:schemas.core:types!/types.xsd"/>

使用以下内容替换'civic'项目的目录文件的内容:

<systemSuffix systemIdSuffix="types.xsd" uri="maven:schemas.core:types!/types.xsd"/>
<systemSuffix systemIdSuffix="automobile.xsd" uri="maven:schemas.vehicle:automobile!/automobile.xsd"/>

请告诉我这是否适合您。

答案 2 :(得分:0)

我遇到了类似的问题。我使用了here找到的示例项目。

我以两种方式修改了这些项目:

1)拥有一个包含2个命名空间和本地目录文件的A项目。根据此项目B使用B中的A集。

2)拥有A项目,B项目和C项目。 B依赖A和C依赖B。

在这两种情况下,我都得到了与你相同的例外情况。但我开始意识到情况2发生了什么。

这是例外: com.sun.istack.SAXParseException2;处理“jar:file:/Users/sjaak/.m2/repository/org/tst/b-working/1.0/b-working-1.0.jar!http://www.a1.org/a1/a1.xsd”时抛出IOException。例外:java.net.MalformedURLException:no!/ in spec。

因此,它在构建项目C时尝试解析相对于项目B的名称空间http://www.a1.org/a1/a1.xsd。我将问题追溯到com.sun.tools.xjc.reader.internalizerAbstractReferenceFinderImpl,方法startElement。

我使用的解决方案是调整org.jvnet.jaxb2.maven2:maven-jaxb2-plugin。我使用了他们的MavenCatalogResolver(如上所述的默认值)并进行了一些小改动,根本没有提供整个systemId:jar:file:/Users/sjaak/.m2/repository/org/tst/b-working/1.0/ b-working-1.0.jar!http://www.a1.org/a1/a1.xsd,但不要使用只提供感叹号后部分的模式进行解析。

以下是代码:

package org.jvnet.jaxb2.maven2.resolver.tools;

import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.MessageFormat;

import org.jvnet.jaxb2.maven2.DependencyResource;
import org.jvnet.jaxb2.maven2.DependencyResourceResolver;

import com.sun.org.apache.xml.internal.resolver.CatalogManager;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MavenCatalogResolver extends
        com.sun.org.apache.xml.internal.resolver.tools.CatalogResolver {

    private final static Pattern PTRN = Pattern.compile("^jar:file:(.*).jar!(.*)$");

    public static final String URI_SCHEME_MAVEN = "maven";
    private final DependencyResourceResolver dependencyResourceResolver;
    private final CatalogManager catalogManager;

    public MavenCatalogResolver(CatalogManager catalogManager,
            DependencyResourceResolver dependencyResourceResolver) {
        super(catalogManager);
        this.catalogManager = catalogManager;
        if (dependencyResourceResolver == null) {
            throw new IllegalArgumentException(
                    "Dependency resource resolver must not be null.");
        }
        this.dependencyResourceResolver = dependencyResourceResolver;
    }

    @Override
    public String getResolvedEntity(String publicId, String systemId) 
    {
        String result;
         Matcher matcher = PTRN.matcher(systemId);
         if (matcher.matches())
         {      
              result = super.getResolvedEntity(publicId, matcher.group(2));
         }
         else
         {
              result = super.getResolvedEntity(publicId, systemId);          
         }
        if (result == null) {
            return null;
        }

        try {
            final URI uri = new URI(result);
            if (URI_SCHEME_MAVEN.equals(uri.getScheme())) {
                final String schemeSpecificPart = uri.getSchemeSpecificPart();
                try {
                    final DependencyResource dependencyResource = DependencyResource
                            .valueOf(schemeSpecificPart);
                    try {
                        final URL url = dependencyResourceResolver
                                .resolveDependencyResource(dependencyResource);
                        String resolved = url.toString();
                        return resolved;
                    } catch (Exception ex) {
                        catalogManager.debug.message(1, MessageFormat.format(
                                "Error resolving dependency resource [{0}].",
                                dependencyResource));
                    }

                } catch (IllegalArgumentException iaex) {
                    catalogManager.debug.message(1, MessageFormat.format(
                            "Error parsing dependency descriptor [{0}].",
                            schemeSpecificPart));

                }
                return null;
            } else {
                return result;
            }
        } catch (URISyntaxException urisex) {

            return result;
        }
    }

}

这实际上解决了我的问题。我会调查一下。我觉得可能会有一些我可以使用的XJC arg,或者目录XML格式提供了更多的可能性。

希望它有所帮助。