在不使用NamespacePrefixMapper的情况下定义Spring JAXB名称空间
[根据理解进展重编辑]
是否有可能让Spring Jaxb2Marshaller使用一组自定义的命名空间前缀(或者至少尊重模式文件/注释中给出的名称空间前缀),而不必使用NamespacePrefixMapper的扩展名?
我们的想法是让一个类与另一个类具有“has”关系,而另一个类又包含具有不同命名空间的属性。 为了更好地说明这一点,请考虑以下使用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"; }
package-info.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()给出以下输出:
而我想要的是:
一旦这部分工作,那么问题就转移到在Spring中配置Jaxb2Marshaller(Spring 2.5.6,spring-oxm-tiger-1.5.6提供Jaxb2Marshaller),以便通过简单的上下文配置提供相同的function。调用marshal()。
感谢您对此问题的持续关注!
[提供JAXB-RI替代方案的一些编辑在本文末尾]
经过多次努力之后,我终于不得不接受我的环境(Windows XP上的JDK1.6.0_12和Mac Leopard上的JDK1.6.0_20)我不能在不诉诸NamespacePrefixMapper的邪恶的情况下完成这项工作。 为什么这是邪恶的? 因为它强制依赖生产代码中的内部JVM类。 这些类不构成JVM和代码之间可靠接口的一部分(即它们在JVM的更新之间发生变化)。
在我看来,Sun应该解决这个问题,或者有更深入了解的人可以添加这个答案 – 请做!
继续。 因为NamespacePrefixMapper不应该在JVM之外使用,所以它不包含在javac的标准编译路径中(由ct.sym控制的rt.jar的子部分)。 这意味着任何依赖它的代码都可能在IDE中编译良好,但在命令行(即Maven或Ant)会失败。 要解决这个问题,必须在构建中明确包含rt.jar文件,如果路径中有空格,Windows似乎也会遇到麻烦。
如果你发现自己处于这个位置,这里有一个Maven片段可以让你摆脱困境:
com.sun.xml.bind jaxb-impl 2.1.9 system C:/temp/rt.jar
注意垃圾硬编码路径到rt.jar的奇怪地方。 您可以通过{java.home} /lib/rt.jar的组合来解决这个问题,它可以在大多数操作系统上运行,但由于Windows空间问题无法保证。 是的,您可以使用配置文件并相应地激活…
或者,在Ant中,您可以执行以下操作:
// Add paths for build.classpath and define {src},{target} as usual
什么是Jaxb2Marshaller Spring配置? 在这里它是完整的,我自己的NamespacePrefixMapper:
弹簧:
org.example.domain
然后我的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中使用上面的邪恶方法,你可能会遇到以下exception:
java.lang.IllegalAccessError:class sun.reflect.GeneratedConstructorAccessor23无法访问其超类sun.reflect.ConstructorAccessorImpl
祝你好运排序。 线索:您的Web服务器的bootclasspath中的rt.jar。
[显示JAXB-RI(参考实现)方法的额外编辑]
如果您能够将JAXB-RI库引入代码中,则可以进行以下修改以获得相同的效果:
主要:
// 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()会产生所需的输出。
(重编辑的回复)
我相信你的代码中的问题是由于一些命名空间URI不匹配。 有时您使用“ http://www.example.org/abc ” ,有时使用“www.example.org/abc” 。 以下应该做的伎俩:
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); System.out.println(jc); 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="http://www.example.org/abc", name="Root_Element") public class RootElement { @XmlElement(namespace = "http://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="http://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"; }
package-info.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()给出以下输出:
@Blaise:你能用这个信息更新MOXy的文档:
在不使用NamespacePrefixMapper的情况下定义Spring JAXB名称空间
我认为没有在那里描述如何配置名称空间前缀。 谢谢!
JDK 7中的JAXB实现支持名称空间前缀。 我试过JDK 1.6.0_21没有运气。