【问题标题】:What is the moxy equivalent to Jackson's JsonAnySetter?与杰克逊的 JsonAnySetter 等效的 moxy 是什么?
【发布时间】:2013-08-06 18:01:45
【问题描述】:

我正在尝试迁移到 Jersey 2.0。这让我对 Jackson 感到很痛苦,文档建议使用 Moxy。

我让 Moxy 为 get 和 post 调用工作,其中一切都很好地匹配,但是我需要处理可能的未知元素。

// Handle unknown deserialization parameters
@JsonAnySetter
protected void handleUnknown(String key, Object value) {
    if (unknownParameters == null) {
        unknownParameters = new HashMap<>();
    }
    unknownParameters.put(key, value);
}

这在更改为 jersey 2.0 之前运行良好,即使当我将它留在其中时它不会引起任何问题,它也不会被调用。

如何在 Jersey 2.0 中实现这一点?我对 Moxy 或 Jackson 没意见。

我的依赖

'org.codehaus.jackson:jackson-mapper-asl:1.9.2',
'org.eclipse.persistence:org.eclipse.persistence.moxy:2.5.0',
'org.glassfish.jersey.media:jersey-media-moxy:2.0',

这对我的 web.xml 没有影响

<init-param>
    <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
    <param-value>true</param-value>
</init-param>

【问题讨论】:

  • 我不知道为什么有人会推荐将 MOXy 用于 JSON(据我所知,它与 Jettison 存在相同的问题);它的 XML 支持可能很好,但 JSON 支持似乎不太好。因此,请确保您知道为什么选择一种实现方式而不是另一种实现方式。

标签: jackson moxy jersey-2.0


【解决方案1】:

注意:我是EclipseLink JAXB (MOXy) 的负责人,也是JAXB (JSR-222) 专家组的成员。

MOXy 没有直接等同于 Jackson 的 @JsonAnySetter。我已输入以下增强请求以添加此类行为:

以下是一些可能适用于您的用例的 MOXy 扩展的一些信息。


MOXy 的@XmlVirtualAccessMethods

如果 JSON 属性不是真的未知,它们只是不作为属性存在于您的域模型中,那么您可以使用 MOXy 的 @XmlVirtualAccessMethods 扩展名(请参阅:http://blog.bdoughan.com/2011/06/extensible-models-with-eclipselink-jaxb.html)。

Java 模型

客户

@XmlVirtualAccess 方法注解用于指定Customer 类是可扩展的。

import java.util.*;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlVirtualAccessMethods;

@XmlVirtualAccessMethods(setMethod = "put")
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {

    private String firstName;
    private Address billingAddress;

    @XmlTransient
    private Map<String, Object> extensions = new HashMap<String, Object>();

    public <T> T get(String property) {
        return (T) extensions.get(property);
    }

    public void put(String property, Object value) {
        extensions.put(property, value);
    }

}

地址

package forum18068176;

public class Address {

    private String street;

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

}

映射文档 (oxm.xml)

扩展属性的定义在 MOXy 的映射文档中定义(参见:http://blog.bdoughan.com/2011/04/moxys-xml-metadata-in-jax-rs-service.html)。

<?xml version="1.0"?>
<xml-bindings
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="forum18068176">
    <java-types>
        <java-type name="Customer">
            <xml-type prop-order="firstName lastName billingAddress shippingAddress"/>
            <java-attributes>
                <xml-element
                    java-attribute="lastName"
                    type="java.lang.String"/>
                <xml-element
                    java-attribute="shippingAddress"
                    type="forum18068176.Address"/>
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>

演示

下面是一些独立的演示代码,您可以运行它来查看一切是如何工作的。您需要将 MOXy 指定为您的 JAXB 提供程序(请参阅:http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html)。

package forum18068176;

import java.util.*;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.jaxb.JAXBContextProperties;

public class Demo {

    public static void main(String[] args) throws Exception {
        Map<String, Object> properties = new HashMap<String, Object>(1);
        properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, "forum18068176/oxm.xml");
        properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
        properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
        JAXBContext jc = JAXBContext.newInstance(new Class[] {Customer.class}, properties);

        // Unmarshal JSON
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        StreamSource json = new StreamSource("src/forum18068176/input.json");
        Customer customer = unmarshaller.unmarshal(json, Customer.class).getValue();

        // Access Extension Properties
        String lastName = customer.<String>get("lastName");
        Address shippingAddress = customer.<Address>get("shippingAddress");

        // Marshal Objects
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(customer, System.out);
    }

}

input.json/Output

{
   "firstName" : "Jane",
   "lastName" : "Doe",
   "billingAddress" : {
      "street" : "1 A Street"
   },
   "shippingAddress" : {
      "street" : "2 B Road"
   }
}

MOXy 的 @XmlVariableNode 扩展,带有 XmlAdapter

如果所有未知项目都属于同一类型,那么您可以使用 MOXy 的@XmlVariableNode(参见:http://blog.bdoughan.com/2013/06/moxys-xmlvariablenode-json-schema.html)和XmlAdapter 的组合来获得所需的结果:

【讨论】:

  • 感谢您提供的出色示例。我正在做的部分工作涉及来自外部来源的数据转换,因此我需要存储未知数以供人们查看。
【解决方案2】:

您可以使用jersey-media-json-jackson 模块而不是 MOXy 来利用注释(我不确定 MOXy 是否支持类似的功能)。只需几个注意事项:

  • web.xml 中删除 com.sun.jersey.api.json.POJOMappingFeature 初始化参数 - Jersey 2.x 无法识别此属性(它是 Jersey 1.x 特有的)
  • 移除org.glassfish.jersey.media:jersey-media-moxy:2.0依赖
  • 添加org.glassfish.jersey.media:jersey-media-json-jackson:2.0 依赖并在您的应用程序中注册JacksonFeature(见下文)

在这些步骤之后,Jackson 应该处理 ObjectJSON (un)marshalling 并且它应该识别 @JsonAnySetter

要在您的应用程序中注册JacksonFeature,请参阅用户指南 (8.1.4 Jackson) 中的专用部分:

// Create JAX-RS application.
final Application application = new ResourceConfig()
        .packages("org.glassfish.jersey.examples.jackson")
        .register(MyObjectMapperProvider.class)  // No need to register this provider if no special configuration is required.
        .register(JacksonFeature.class);

【讨论】:

【解决方案3】:

Jersey 2.0 应该可以与来自 https://github.com/FasterXML/jackson-jaxrs-providers 的未经修改的 Jackson 2.x JAX-RS 提供程序一起正常工作。无需通过 web.xml 进行任何配置,因为提供者使用服务提供者接口。唯一的潜在问题来自同一媒体类型的多个提供商。

只需确保使用 Jackson 依赖项的 2.x(如 2.2.2)版本即可。虽然 Jackson 1.x 和 2.x 版本可以共存,但模块之间的依赖关系必须匹配(即 2.2 JAX-RS 提供程序依赖于 2.2 jackson-core 和 jackson-databind jar)。

【讨论】:

  • 反对票是为了……? (考虑到部分“我对 Moxy 或 Jackson 很好”)
  • 不知道为什么这没有得到更多的选票 - 自动注册工作完美。
猜你喜欢
  • 2019-07-07
  • 1970-01-01
  • 2011-08-25
  • 1970-01-01
  • 2022-12-08
  • 2014-08-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多