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

Java 在不使用NamespacePrefixMapper的情况下定义Spring JAXB命名空间,java,xml,spring,jaxb,Java,Xml,Spring,Jaxb,[随着理解的进展,大量编辑] 是否可以让Spring Jaxb2Marshaller使用一组自定义的名称空间前缀(或者至少尊重模式文件/注释中给出的前缀),而不必使用名称空间前缀apper的扩展名 其思想是让一个类与另一个类具有“has a”关系,而另一个类又包含一个具有不同命名空间的属性。为了更好地说明这一点,请考虑以下项目大纲:使用JDK1.60EY12(最近我可以在工作中得到我的手)。我在包org.example.domain中有以下内容: Main.java: package org.e

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

是否可以让Spring Jaxb2Marshaller使用一组自定义的名称空间前缀(或者至少尊重模式文件/注释中给出的前缀),而不必使用名称空间前缀apper的扩展名

其思想是让一个类与另一个类具有“has a”关系,而另一个类又包含一个具有不同命名空间的属性。为了更好地说明这一点,请考虑以下项目大纲:使用JDK1.60EY12(最近我可以在工作中得到我的手)。我在包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()将提供以下输出:

<?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:abc="http://www.example.org/abc" xmlns:xlink="http://www.w3.org/1999/xlink">
    <abc:childElementWithXlink xlink:href="http://www.example.org"/>
</abc: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中配置Jaxb2Marshaller(Spring 2.5.6,Spring-oxm-tiger-1.5.6提供Jaxb2Marshaller),以便通过简单的上下文配置和对marshal()的调用提供相同的配置

感谢您对这个问题的持续关注

(经过大量编辑的回复)

我相信代码中的问题是由于某些命名空间URI不匹配造成的。有时您使用的是,有时使用的是“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()将提供以下输出:

<?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:abc="http://www.example.org/abc" xmlns:xlink="http://www.w3.org/1999/xlink">
    <abc:childElementWithXlink xlink:href="http://www.example.org"/>
</abc:Root_Element>

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

好吧,在费了很多脑筋之后,我终于不得不承认,对于我的环境(Windows XP上的JDK1.6.0_12和Mac Leopard上的JDK1.6.0_20),如果不借助名称空间前缀Xmapper,我就无法实现这一点。为什么它是邪恶的?因为它强制您在生产代码中依赖内部JVM类。这些类不构成JVM和代码之间可靠接口的一部分(即,它们在JVM更新之间发生变化)

在我看来,Sun应该解决这个问题,或者有更深入的知识的人可以补充这个答案-请这样做

继续。因为NamespacePrefixMapper不应该在JVM之外使用,所以它不包括在javac的标准编译路径中(rt.jar的一个子部分,由ct.sym控制)。这意味着任何依赖于它的代码都可能在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>
嗯,就在那里。我希望这能帮助别人避免我所经历的痛苦。哦,顺便说一下,如果您在Jetty中使用上述邪恶方法,您可能会遇到以下例外情况:

java.lang.IllegalAccessError:class sun.reflect.GeneratedConstructorAccessor23无法访问其超类sun.reflect.ConstructorAccessorImpl

祝你好运,把这件事解决掉。提示:web服务器的bootclasspath中的rt.jar

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

如果能够在代码中引入,则可以进行以下修改以获得相同的效果:

主要内容:

MyNamespacePrefixMapper:

// Change the import to this
import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
从/lib文件夹中从JAXB-RI下载添加以下JAR(跳过许可证限制之后):

jaxb-impl.jar

运行Main.Main()会得到所需的输出。

@Blaise:您能用以下信息更新MOXy的文档吗:

我认为这里没有描述如何配置名称空间前缀。
谢谢

jdk7中的JAXB实现支持名称空间前缀。我用JDK 1.6.0_21尝试过,但运气不佳。

你能用一个普通的
JAXBContext
,也就是说,不涉及Spring吗?看起来
Jaxb2Marshaller
与问题无关。另外,您正在使用哪些JDK和/或JAXB版本?(p.s.嗨,加里:)嗨,斯卡夫曼:-)按要求做了编辑。这真让我抓狂。谢谢布莱斯对这件事的关注。为了更好地回答你的问题,我对原来的帖子做了一些修改。您会注意到,我添加了一个具有不同名称空间(XLink)的子元素,我在最初的帖子中没有明确说明这一点(很抱歉)。嗨,Blaise,我曾尝试使用更新的RootElement类复制您的结果,但不幸的是,如果所有其他代码都与我在帖子中所述的相同,那么它将使用额外的(ns3)名称空间失败。您介意回顾一下我发布的内容以确保它仍然符合您的设置吗?谢谢您的帮助:)我错过了额外的ns3命名空间声明。如果使用XLink从ChildElement中删除@XmlRootElement,它将消失(请参见上面编辑的答案)。你的模型需要那个注释吗?嗨,布莱斯。我又一次试图达到和你一样的目的,但还是失败了。我就是离不开“ns1”名称空间而不是“xlink”。我已经在Windows XP上的JDK 1.6.0_12和Mac上的JDK 1.6.0_20上进行了尝试,两者都给出了相同的结果。我确实使用了问题中的代码,加上你的编辑,但是我的结果不同。我想您使用的是不同的JDK或操作系统。你介意澄清一下你的环境吗?我必须承认,我开始对这一切都失去了希望。嗨,加里,我已经重做了我的答案。看起来最终您有时会使用名称空间“”,而有时使用“www.example.org/abc”,这会导致额外的名称空间声明。我的env是WindowsXP上的JDK1.6.020。另一种选择是使用JAXB-RI,而不是JDK1.6内置的。这样,您就得到了一个可预测的类路径
// Change the import to this
import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
jaxb-impl.jar