gpt4 book ai didi

java - 在不使用 NamespacePrefixMapper 的情况下定义 Spring JAXB 命名空间

转载 作者:IT老高 更新时间:2023-10-28 13:47:15 25 4
gpt4 key购买 nike

[随着理解的进展进行了大量编辑]

是否可以让 Spring Jaxb2Marshaller 使用一组自定义的命名空间前缀(或至少尊重架构文件/注释中给出的前缀)而不必使用 NamespacePrefixMapper 的扩展?

这个想法是让一个类与另一个类具有“具有”关系,而另一个类又包含一个具有不同命名空间的属性。为了更好地说明这一点,请考虑以下使用 JDK1.6.0_12 的项目大纲(我可以在工作中得到的最新版本)。我在包 org.example.domain 中有以下内容:

Main.java:

package org.example.domain;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

public class Main {
public static void main(String[] args) throws JAXBException {
JAXBContext jc = JAXBContext.newInstance(RootElement.class);

RootElement re = new RootElement();
re.childElementWithXlink = new ChildElementWithXlink();

Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(re, System.out);
}

}

RootElement.java:

package org.example.domain;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(namespace = "www.example.org/abc", name="Root_Element")
public class RootElement {
@XmlElement(namespace = "www.example.org/abc")
public ChildElementWithXlink childElementWithXlink;

}

ChildElementWithXLink.java:

package org.example.domain;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSchemaType;

@XmlRootElement(namespace="www.example.org/abc", name="Child_Element_With_XLink")
public class ChildElementWithXlink {
@XmlAttribute(namespace = "http://www.w3.org/1999/xlink")
@XmlSchemaType(namespace = "http://www.w3.org/1999/xlink", name = "anyURI")
private String href="http://www.example.org";

}

包信息.java:

@javax.xml.bind.annotation.XmlSchema(
namespace = "http://www.example.org/abc",
xmlns = {
@javax.xml.bind.annotation.XmlNs(prefix = "abc", namespaceURI ="http://www.example.org/abc"),
@javax.xml.bind.annotation.XmlNs(prefix = "xlink", namespaceURI = "http://www.w3.org/1999/xlink")
},
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package org.example.domain;

运行 Main.main() 给出以下输出:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:Root_Element xmlns:ns1="http://www.w3.org/1999/xlink" xmlns:ns2="www.example.org/abc">
<ns2:childElementWithXlink ns1:href="http://www.example.org"/>
</ns2:Root_Element>

而我想要的是:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<abc:Root_Element xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:abc="www.example.org/abc">
<abc:childElementWithXlink xlink:href="http://www.example.org"/>
</abc:Root_Element>

一旦这部分工作正常,问题就会转移到在 Spring(Spring 2.5.6,spring-oxm-tiger-1.5.6 提供 Jaxb2Marshaller)中配置 Jaxb2Marshaller,以便它通过简单的方式提供相同的上下文配置和对 marshal() 的调用。

感谢您一直关注这个问题!

最佳答案

[提供 JAXB-RI 替代方案的一些编辑在本文末尾]

经过多次挠头后,我终于不得不接受对于我的环境(Windows XP 上的 JDK1.6.0_12 和 Mac Leopard 上的 JDK1.6.0_20)我不能不诉诸邪恶的情况下完成这项工作是命名空间前缀映射器。为什么是邪恶的?因为它在生产代码中强制依赖内部 JVM 类。这些类不构成 JVM 和您的代码之间的可靠接口(interface)的一部分(即它们在 JVM 更新之间发生变化)。

在我看来,Sun 应该解决这个问题,或者有更深知识的人可以添加到这个答案中 - 请这样做!

继续前进。因为 NamespacePrefixMapper 不应该在 JVM 之外使用,所以它不包含在 javac 的标准编译路径(由 ct.sym 控制的 rt.jar 的子部分)中。这意味着任何依赖它的代码都可能在 IDE 中编译得很好,但在命令行(即 Maven 或 Ant)会失败。为了克服这个问题,rt.jar 文件必须显式包含在构建中,即使这样,如果路径中有空格,Windows 似乎也会遇到问题。

如果你发现自己处于这个位置,这里有一个 Maven 片段可以帮助你摆脱困境:

<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.1.9</version>
<scope>system</scope>
<!-- Windows will not find rt.jar if it is in a path with spaces -->
<systemPath>C:/temp/rt.jar</systemPath>
</dependency>

注意 rt.jar 到一个奇怪的地方的垃圾硬编码路径。您可以通过结合使用 {java.home}/lib/rt.jar 来解决这个问题,这将在大多数操作系统上运行,但由于 Windows 空间问题并不能保证。是的,您可以使用配置文件并相应地激活...

或者,在 Ant 中,您可以执行以下操作:

<path id="jre.classpath">
<pathelement location="${java.home}\lib" />
</path>
// Add paths for build.classpath and define {src},{target} as usual
<target name="compile" depends="copy-resources">
<mkdir dir="${target}/classes"/>
<javac bootclasspathref="jre.classpath" includejavaruntime="yes" debug="on" srcdir="${src}" destdir="${target}/classes" includes="**/*">
<classpath refid="build.classpath"/>
</javac>
</target>

那么 Jaxb2Marshaller Spring 配置呢?好了,这里有我自己的 NamespacePrefixMapper:

Spring :

<!-- JAXB2 marshalling (domain objects annotated with JAXB2 meta data) -->
<bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="contextPaths">
<list>
<value>org.example.domain</value>
</list>
</property>
<property name="marshallerProperties">
<map>
<!-- Good for JDK1.6.0_6+, lose 'internal' for earlier releases - see why it's evil? -->
<entry key="com.sun.xml.internal.bind.namespacePrefixMapper" value-ref="myCapabilitiesNamespacePrefixMapper"/>
<entry key="jaxb.formatted.output"><value type="boolean">true</value></entry>
</map>
</property>
</bean>

<!-- Namespace mapping prefix (ns1->abc, ns2->xlink etc) -->
<bean id="myNamespacePrefixMapper" class="org.example.MyNamespacePrefixMapper"/>

然后是我的 NamespacePrefixMapper 代码:

public class MyNamespacePrefixMapper extends NamespacePrefixMapper {

public String getPreferredPrefix(String namespaceUri,
String suggestion,
boolean requirePrefix) {
if (requirePrefix) {
if ("http://www.example.org/abc".equals(namespaceUri)) {
return "abc";
}
if ("http://www.w3.org/1999/xlink".equals(namespaceUri)) {
return "xlink";
}
return suggestion;
} else {
return "";
}
}
}

嗯,就是这样。我希望这可以帮助某人避免我所经历的痛苦。哦,顺便说一句,如果你在 Jetty 中使用上述邪恶的方法,你可能会遇到以下异常:

java.lang.IllegalAccessError: 类 sun.reflect.GeneratedConstructorAccessor23 无法访问其父类(super class) sun.reflect.ConstructorAccessorImpl

祝你好运。提示:您的 Web 服务器的引导类路径中的 rt.jar。

[显示 JAXB-RI(引用实现)方法的额外编辑]

如果您能够介绍 JAXB-RI libraries在您的代码中,您可以进行以下修改以获得相同的效果:

主要:

// Add a new property that implies external access
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new MyNamespacePrefixMapper());

MyNamespacePrefixMapper:

// Change the import to this
import com.sun.xml.bind.marshaller.NamespacePrefixMapper;

从/lib 文件夹中的 JAXB-RI 下载(跳过许可证箍之后)添加以下 JAR:

jaxb-impl.jar

运行 Main.main() 会产生所需的输出。

关于java - 在不使用 NamespacePrefixMapper 的情况下定义 Spring JAXB 命名空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3289644/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com