当前位置: 首页 > 知识库问答 >
问题:

如何在不改变模型的情况下向Jersey/Moxy/jaxbxml添加结构链接

诸葛嘉熙
2023-03-14

我指的是HATEOAS/超媒体应用编程接口意义上的“结构链接”。更一般的问题是如何使用既依赖于被封送的实体,又依赖于环境(在本例中,至少是绝对URL)的数据来扩充生成的XML。

我正在使用与Moxy 2.5一起使用的泽西2.9作为JAXB提供程序。

根据该模型:

package testing;

import java.util.ArrayList;
import java.util.List;

public class Planet {

    private int id = 1;
    private String name = "test";
    private double radius = 3.0;
    private String href;

    private List<Moon> moons = new ArrayList<Moon>(0);

    public void addMoon(Moon moon) {
        moons.add(moon);
    }
}

...plus Moon class

我想得到这样的XML(以及等效的JSON):

<planet href="http://mytestserver/rest/planets/test">
    <name>test</name>
    <radius>3.0</radius>
    <moons>
        <moon href="http://mytestserver/rest/moons/moon1">
            <name>moon1</name>
        </moon>
        <moon href="http://mytestserver/rest/moons/moon2">
            <name>moon2</name>
        </moon>
    </moons>
</planet>

模型没有“href”字段,也不能添加一个。理想情况下,我可以使用UriBuilder直接从资源类中抓取这些路径。

到目前为止,我已经提出了几种可能性。我能要求你考虑哪一个(如果有的话)有最多的腿,然后你怎么处理这个方法的缺点呢?

然后使用Jersey中现有的声明性链接机制,所有这些机制都依赖于模型中有一个字段来接收生成的链接。如果在构建过程中没有AspectJ和/或对字节码操纵等外来技术犹豫不决,那么这显然是行不通的。

例如,在MessageBodyWriter中:

ContextResolver<JAXBContext> resolver = providers.getContextResolver(JAXBContext.class, mediaType);
JAXBContext context = resolver.getContext(type);
Marshaller m = context.createMarshaller();
<--- here, marshall to e.g. a DOM then transform that
<--- then manipulate the JSON structures

我完全不知道如何做到这一点,因此缺少代码。可能还有其他方法可以钩住XML生成过程,但据我所知,Jersey或JAXB的事件处理程序或拦截器实际上都不允许您操作生成的XML/JSON。

例如:

XML binding:
<java-type name="Planet" xml-customizer="testing.HrefCustomizer">

Customizer:
public class HrefCustomizer implements DescriptorCustomizer {

    @Override
    public void customize(ClassDescriptor descriptor) throws Exception {
        XMLTransformationMapping xtm = new XMLTransformationMapping();
        xtm.addFieldTransformer("@href", new HrefWriter());

        descriptor.addMapping(xtm);

    }

}

Transformer:
public class HrefWriter implements FieldTransformer {

    @Override
    public Object buildFieldValue(Object instance, String fieldName,
            Session session) {
        return "href";  // constant value just for proof-of-concept
    }

    @Override
    public void initialize(AbstractTransformationMapping mapping) {
        // TODO Auto-generated method stub

    }

}

这种方法有两个问题:

  1. 很难找到关于它的任何文档,我想知道它是否实际上是不受支持的用法

如果我们决定不能在实例化时为变压器提供任何有意义的上下文,定制程序将不会增加任何值,我们可以将上面的内容简化为以下内容:

    <java-type name="Planet">
        <xml-root-element/>            
        <java-attributes>
            <xml-transformation java-attribute="name">
                <xml-write-transformer transformer-class="testing.HrefWriter" xml-path="@href"/>
            </xml-transformation>
            <xml-element java-attribute="name"/>

有点奇怪的是,我们将变压器挂在另一个字段上(本例中为“名称”)。

或者,我完全找错人了。救命啊!!

共有1个答案

况繁
2023-03-14
  • 使用AbulJ向模型类添加一个字段(在本例中称为href)
  • 将泽西@InjectLink注释添加到该字段
  • 然后,泽西将使用资源类定义的正确URL填充字段
  • 使用外部映射文件指定href字段的封送处理。

您还可以通过相同的AspectJ类型间声明机制向href添加JAXB注释来指定href的封送。

这些是信息量最大的部分。看见http://lagod.id.au/blog/?p=494完整的例子。

package testing;

import org.glassfish.jersey.linking.InjectLink;
import org.glassfish.jersey.linking.Binding;

public aspect HrefInjector {

    private String Planet.href;
    declare @field : * Planet.href : @InjectLink(
                                        resource=Services.class, 
                                        style=InjectLink.Style.ABSOLUTE
                                    ) ;

    private String Moon.href;
    declare @field : * Moon.href : @InjectLink(
                                        resource=Services.class,
                                        method="moon",
                                        bindings={@Binding(
                                                name="moonid", value="${instance.name}"
                                                )},
                                        style=InjectLink.Style.ABSOLUTE
                                    ) ;

}

不含其他特定积垢的POJO。请参见Jersey Moxy JAXB-如何封送不带注释的XML。

package testing;

import java.util.ArrayList;
import java.util.List;

public class Planet {

    private int id = 1;
    private String name = "test";
    private double radius = 3.0;

    private List<Moon> moons = new ArrayList<Moon>(0);

    public void addMoon(Moon moon) {
        moons.add(moon);
    }
}


package testing;

public class Moon {

    private String name;

    // No-arg constructor is a requirement of JAXB
    public Moon() {
    }

    public Moon(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

}

这是一个标准的JAX-RS资源类。出于演示目的,我们只是返回新实例化的模型实例。

package testing;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/services")
@Produces({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
public class Services {

    private Planet initPlanet() {
        Planet p = new Planet();
        p.addMoon(new Moon("moon1"));
        p.addMoon(new Moon("moon2"));
        return p;
    }

    @GET
    public Planet planet () {
        return initPlanet();
    }

    @GET @Path("/moons/{moonid}")
    public Moon moon (@PathParam("moonid") String name) {
        return new Moon(name);
    }

}

请注意,您可以为任何给定类型选择是否实际封送href字段。事实上,通过使用多个映射文件,您可以在某些表示中包含href字段,而不在其他表示中包含href字段。

<?xml version="1.0"?>
<xml-bindings
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="testing"
    xml-mapping-metadata-complete="true"
    xml-accessor-type="NONE">
    <java-types>
        <java-type name="Planet">
            <xml-root-element/>
            <java-attributes>
                <xml-attribute java-attribute="href"/>
                <xml-element java-attribute="name"/>
                <xml-element java-attribute="radius"/>
                <xml-element java-attribute="moons" name="moon">
                    <xml-element-wrapper name="moons"/>
                </xml-element>    
            </java-attributes>
        </java-type>
        <java-type name="Moon">
            <xml-root-element/>
            <java-attributes>
                <xml-attribute java-attribute="href"/>
                <xml-element java-attribute="name"/>
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>

Ta-dah!自动从JAX-RS资源类派生的结构链接,而无需更改模型源代码。因为我们使用Moxy,所以我们也可以免费获得JSON。

<planet href="http://localhost:8080/reststructlinks/rest/services">
    <name>test</name>
    <radius>3.0</radius>
    <moons>
        <moon href="http://localhost:8080/reststructlinks/rest/services/moons/moon1">
            <name>moon1</name>
        </moon>
        <moon href="http://localhost:8080/reststructlinks/rest/services/moons/moon2">
            <name>moon2</name>
        </moon>
    </moons>
</planet>
 类似资料:
  • 虽然我的问题主题似乎是许多PDF操作包和工具都支持的特性,但我需要明确指出,我不想旋转PDF。 我有一个PDF,它显示了一个纵向(A4),尺寸为WxH 297x210(A4旋转)。 现在,我需要实现的是,这个PDF有横向方向,同时保留尺寸。 我不确定这需要我做什么。 如果我使用Adobe Illustrator将文档格式更改到所需的位置,我还需要旋转内容。如果我将此页面放入设计糟糕的PDF中,此页

  • 或者(甚至更好)在调用之前以某种方式截取序列化,例如: 我想我可以扩展并重写它的方法,但它被声明为,而且我找不到一种简单的方法来创建的新实例,而不为它提供所有类型元数据细节,这实际上是复制Jackson的一个很好的部分。所以我已经放弃了。 我的问题是-如何定制Jackson的序列化,为特定POJO向JSON输出添加额外的内容,而不引入太多的样板代码,并尽可能多地重用默认的Jackson行为。

  • 问题内容: 我想知道是否有任何方法可以将C ++类公开给Python,但无需构建中间共享库。 这是我理想的情况。例如,我有以下C ++类: 我想以某种方式将此类(或其实例)转换为PyObject *,以便将其作为参数(参数)发送给例如PyObject_CallObject: 另一方面,在python端,我有一个wrapperFunction,它将我的C ++类(或其实例)上的指针作为参数,并调用其

  • 问题内容: 我正在使用Jackson将应用程序的REST接口序列化为JSON表示形式的POJO域对象。我想为某些类型自定义序列化,以将其他属性添加到POJO中不存在的JSON表示中(例如,添加一些元数据,参考数据等)。我知道如何编写自己的方法,但是在那种情况下,我需要为对象的 每个* 属性显式调用方法,而我所需要的只是 添加 一个附加属性。换句话说,我希望能够编写如下内容: *** 或者(甚至更好

  • 我想从JSON响应中添加链接:https://xxx.xxx/posters/poster.jpg,这里是我的代码: 下面是JSON响应: 如何让它变成这样:

  • 问题内容: 我希望能够以不同于web.xml的方式修改/配置过滤器。这是2个过滤器的静态配置。我希望能够静态配置一个过滤器,并允许该过滤器加载其他过滤器。我只是想知道是否有人知道lib已有此功能。 使用Servlet API 2.5 我已经在Guice的GuiceFilter中完成了此操作,其中在运行时配置了过滤器。 问题答案: 只需执行与容器已完成的相同的工作即可。即,按照servlet过滤器所