4

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

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

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

汽车项目依赖于类型项目中的模式。这是其目录文件 ( catalog.xml ) 中的条目:

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

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

我还使用情节来防止类型中的类在汽车项目中重新生成。这是我的pom.xml的一个片段:

<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.xsdauto.xsd。我使用目录文件 ( catalog.xml ) 来定义模式的位置:

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

我使用剧集来防止类的重新生成。这是来自pom.xmlcivic的片段:

<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最终会包含依赖模块中的所有类型(这是我试图通过使用剧集来避免的事情)。

公民项目生成的java类

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

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

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

公民: http: //pastebin.com/eGSVGwmE

4

3 回答 3

3

这里的作者maven-jaxb2-plugin

我刚刚发布0.10.0. maven-jaxb2-plugin此版本修复了与报告的问题相关的MAVEN_JAXB2_PLUGIN-82问题。

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

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

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

maven-jaxb2-plugin我现在已经实施了相当可靠的解决方法。在此处查看此测试项目:

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

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

REWRITE_SYSTEM "http://www.ab.org" "maven:org.jvnet.jaxb2.maven2:maven-jaxb2-plugin-tests-MAVEN_JAXB2_PLUGIN-82-a:jar::!"

现在工作正常。

如果出现问题mvn -X并检查输出,您还将在日志中看到目录解析器的语句。这可能会给你提示,什么不起作用。

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

https://github.com/highsource/w3c-schemas

来自 POM 的片段:

                    <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>

目录:

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中。
  • 该项目要编译 URL http://www.w3.org/1999/xlink.xsd
  • 目录将此 URL 重写为 systemId maven:org.hisrc.w3c:w3c-schemas:jar::!/w3c/1999/xlink.xsd。(罐子里有一个/w3c/1999/xlink.xsd资源)。w3c-schemas
  • 然后这个 systemId 被我的 Maven 目录解析器(传递给我的maven-jaxb2-plugin)解析为“真实”的 URL,这将是一些jar:...指向w3c-schemas本地存储库中工件 JAR 中资源的 URL。
  • 因此,模式不是从 Internet 下载的,而是从本地资源中获取的。
  • 解决方法保留“原始”系统 ID,因此您可以使用其原始 URL 自定义架构。(解析的 systemId 不方便。)
  • 目录文件和全局绑定文件对于所有单个项目都是相同的,因此它们也被放入中央工件并使用dependencyResource.
于 2014-10-05T22:47:45.057 回答
0

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

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

从 poms.xml 的插件配置中删除 '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"/>

让我知道这是否适合您。

于 2013-08-14T21:38:29.900 回答
0

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

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

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 时抛出 IOException .xsd ”。异常:java.net.MalformedURLException:没有!/ 在规范中。

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

我使用的解决方案是调整 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 格式提供了更多可能性。

希望能帮助到你。

于 2013-10-22T20:55:53.497 回答