如何自定义 Jersey JAXB 序列化的 XML 输出

发布于 2024-11-29 05:09:53 字数 254 浏览 1 评论 0原文

我有一些 @javax.xml.bind.annotation.Xml... 带注释的类,用于 REST Web 服务。 Jersey 设置在 Spring 管理的 Web 容器中,并且 Web 服务返回格式良好的 xml。我们使用 maven-enunciate-plugin 来记录 Web 服务并为返回的 xml 文档创建 xsd。我现在想使用文档 xsd 文件作为返回的 xml 文件中的 schemaLocation,以便 xml 验证不会抱怨缺少定义。如何为此配置 XML 序列化?

I have some @javax.xml.bind.annotation.Xml... annotated classes here intended for a RESt web service. Jersey is setup in a spring managed web container and the web service is returning a well formatted xml. We use the maven-enunciate-plugin to document the web service and create the xsd to the returned xml documents. I now would like to use the documentation xsd file as a schemaLocation within the returned xml file so that the xml validation won't complain about missing definions. How can I get the XML serialisation configured for this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

乙白 2024-12-06 05:09:53

如果我没记错的话,我必须做一些事情才能将命名空间标识符正确写入生成的 XML 中。

1) 创建一个 JaxbFactory 来配置并返回一个自定义编组器(顺便说一句,还有解组器)。我省略了下面的吸气剂/和解组设置...

//constructor
public JaxbFactory() throws Exception {
    context = JAXBContext.newInstance(ResourceDto.class);

    // Setup the marshaller
    marshaller = context.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
    marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, XmlMetadataConstants.XML_SCHEMA_LOCATION);  // this schema location is used in generating the schema-location property in the xml
}

2) 该工厂类对 Jersey 来说是“不可见的”。为了使其可见,我创建了一个 MarshallerProvider。看起来像这样:

@Provider
public class ResourceJaxbMarshallerProvider implements ContextResolver<Marshaller> {
// injected by Spring
private ResourceJaxbFactory ResourceJaxbFactory;
private ResourceStatusJaxbFactory ResourceStatusJaxbFactory;


/*
 * ----------------------------------------
 * Setters (for Spring injected properties)
 * ----------------------------------------
 */
public void setResourceJaxbFactory(ResourceJaxbFactory ResourceJaxbFactory) {
    this.ResourceJaxbFactory = ResourceJaxbFactory;
}

public void setResourceStatusJaxbFactory(ResourceStatusJaxbFactory ResourceStatusJaxbFactory) {
    this.ResourceStatusJaxbFactory = ResourceStatusJaxbFactory;
}

/*
 * ------------------------
 * Interface Implementation
 * ------------------------
 */
public Marshaller getContext(Class<?> type) {
    if (type == ResourceDto.class)
        return ResourceJaxbFactory.getMarshaller();
    else if (type == ResourceStatusDto.class)
        return ResourceStatusJaxbFactory.getMarshaller();
    else
        return null;
}       
}

我已经使用 Jersey/Spring Servlet 将 Jersey 连接到 Spring,因此由 Spring 创建的任何 @Provider 类都会被 Jersey 自动识别。在我的 Spring applicationContext.xml 中,我所要做的就是实例化资源提供程序。反过来,它会从工厂中获取编组器。

3)我发现另一件至关重要的事情是我必须在包含我的资源的根包中创建一个 package-info.java 文件。看起来像这样:

/*
 * Note that this file is critical for ensuring that our ResourceDto object is
 * marshalled/unmarshalled with the correct namespace.  Without this, marshalled
 * classes produce XML files without a namespace identifier
 */
@XmlSchema(namespace = XmlMetadataConstants.XML_SCHEMA_NAMESPACE, elementFormDefault = XmlNsForm.QUALIFIED) 
package com.yourcompany.resource;

import javax.xml.bind.annotation.XmlNsForm;

至少我认为这就是我需要做的一切,我无法记住每一件作品。我确实记得 package-info.java 部分是使所有内容组合在一起的最后一个关键齿轮。

希望有帮助。我花了太多时间挖掘这一切的信息。在我希望 Jersey 进行正确的 xml 模式验证(以及针对模式无效输入的正确错误报告)之前,Jersey 非常简单。一旦我开始沿着这条路走下去,泽西岛就从简单的脑死亡变得相当困难。大部分困难在于从网上各种帖子中找出所有细节。希望这能帮助您走得更远、更快。 :-)

If I remember correctly, I had to do a few of things to get namespace identifiers properly written into my generated XML.

1) Created a JaxbFactory that configs and returns a custom marshaller (and unmarshaller, too, BTW). I'm omitting the getters/and unmarshalling setup below...

//constructor
public JaxbFactory() throws Exception {
    context = JAXBContext.newInstance(ResourceDto.class);

    // Setup the marshaller
    marshaller = context.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
    marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, XmlMetadataConstants.XML_SCHEMA_LOCATION);  // this schema location is used in generating the schema-location property in the xml
}

2) That factory class isn't "visible" to Jersey. To make it visible, I create a MarshallerProvider. That looks something like this:

@Provider
public class ResourceJaxbMarshallerProvider implements ContextResolver<Marshaller> {
// injected by Spring
private ResourceJaxbFactory ResourceJaxbFactory;
private ResourceStatusJaxbFactory ResourceStatusJaxbFactory;


/*
 * ----------------------------------------
 * Setters (for Spring injected properties)
 * ----------------------------------------
 */
public void setResourceJaxbFactory(ResourceJaxbFactory ResourceJaxbFactory) {
    this.ResourceJaxbFactory = ResourceJaxbFactory;
}

public void setResourceStatusJaxbFactory(ResourceStatusJaxbFactory ResourceStatusJaxbFactory) {
    this.ResourceStatusJaxbFactory = ResourceStatusJaxbFactory;
}

/*
 * ------------------------
 * Interface Implementation
 * ------------------------
 */
public Marshaller getContext(Class<?> type) {
    if (type == ResourceDto.class)
        return ResourceJaxbFactory.getMarshaller();
    else if (type == ResourceStatusDto.class)
        return ResourceStatusJaxbFactory.getMarshaller();
    else
        return null;
}       
}

I've got Jersey wired into Spring using the Jersey/Spring Servlet so any @Provider class that gets created by Spring is automatically recognized by Jersey. In my Spring applicationContext.xml all I have to do is instantiate the resource provider. It will, in turn, go grab the marshaller from the factory.

3) The other thing that I found critical was that I had to create a package-info.java file in the root package containing my resource. Looks like this:

/*
 * Note that this file is critical for ensuring that our ResourceDto object is
 * marshalled/unmarshalled with the correct namespace.  Without this, marshalled
 * classes produce XML files without a namespace identifier
 */
@XmlSchema(namespace = XmlMetadataConstants.XML_SCHEMA_NAMESPACE, elementFormDefault = XmlNsForm.QUALIFIED) 
package com.yourcompany.resource;

import javax.xml.bind.annotation.XmlNsForm;

At least I think that's everything I needed to do, I can't remember every single piece. I do remember that the package-info.java piece was the last critical cog that made it all come together.

Hope that helps. I spent wayyyy too much time digging for the info on all this. Jersey was seductively simple before I wanted it to do proper xml schema validation (and decent error reporting for schema-invalid input). Once I started down that road Jersey went from brain-dead easy to decently hard. The majority of that difficulty was sussing out all the details from the variety of posts online. Hopefully this will help get you farther, quicker. :-)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文