泽西岛(哈希)地图的序列化程序使用? [英] Serializer for (Hash)Maps for Jersey use?

查看:93
本文介绍了泽西岛(哈希)地图的序列化程序使用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将以下有效负载发布到基于Jersey的网络服务:

I'm trying to POST the following payload to my Jersey-based web service:

{
    "firstname":"Jimmy",
    "lastname":"Johns",
    "addresses":
    [
        {
            "street":"19 Mayberry Drive",
            "city":"Mayberry",
            "state":"nc",
            "postalcode":"27043",
            "country":"us",
            "addresstype":1
        }
    ],
    "data":
    {
        "eyes":"blue",
        "hair":"brown",
        "sandwich":"roast beef"
    }
}

我的泽西岛代码:

@POST
public Response create( Person person )
{
    createBo( person );    <------- stopped here in debugger
    ...

停止就像泽西岛给我打电话一样,我看到 person 中的地址正好与我正在寻找的东西一样(上面的JSON中有什么)。但是,我的数据元组不存在。我知道泽西岛正在为地址 es调用我的无法构造函数,并且它的安装程序正在被调用,但是我在夜间对泽西岛可能会或可能不会尝试这些我的JSON中的随机(数据)元组。 (我说随机,因为在不同的调用中,这些可能是洞穴:深,黑,山:高,宽等。这是我界面的一部分。)

Stopped just as Jersey calls me, I see addresses in person flushed out with exactly what I'm looking for (what's in the JSON above). However, my data tuples aren't there. I know Jersey is calling my no-arg constructor for Address es and its setters are getting called, but I'm up in the night as far as what Jersey might or might not be trying to do with these random ("data") tuples in my JSON. (I say "random" because in a different invocation, these might be "cave":"deep, dark", "mountain":"high, wide", etc. This is part and parcel of my interface.)

为了充实我正在谈论的内容,请将这些POJO视为上述内容:

To flesh out what I'm talking about, consider these POJOs as context for the above:

@XmlAccessorType( XmlAccessType.FIELD )
@XmlRootElement
public class Person implements Serializable
{
    @XmlElement
    private List< Address > addresses = new ArrayList< Address >();

    @XmlElement
    private Map< String, String > data = new HashMap< String, String >();

    ...

@XmlRootElement
public class Address implements Serializable
{
    private String  street;
    private String  city;
    private String  state;
    private String  country;
    private String  postalcode;
    private Integer addresstype;
    ...

注意:我不能像我那样做随机元组完成地址因为我事先并不知道密钥是什么(而我将地址限制为 street city 等等。

Note: I can't do the random tuples as I've done Address because I don't actually know beforehand what the keys will be (whereas I limit Address to street, city, etc.).

我需要的是泽西的 HashMap 的某种魔术序列化器,我似乎无法解释docs足以理解如何写一个或解决这个问题,同时仍然保持我的界面的灵活性。

What I need is some kind of magic serializer for HashMaps in Jersey and I cannot seem to interpret the docs well enough to understand how to write one or work around this problem while still maintaining the flexibility of my interface.

我将很感激如何实现这一点。

I would appreciate any indication as to how to accomplish this.

Russ Bateman

Russ Bateman

PS遗憾地注意到 Java.util.Map to JSON Object with泽西/ JAXB /杰克逊没有帮助,虽然它显示了很大的希望。

P.S. Note sadly that Java.util.Map to JSON Object with Jersey / JAXB / Jackson was not helpful, though it showed great promise.

推荐答案

注意:我是 EclipseLink JAXB(MOXy) 领导和 JAXB(JSR-222)的成员专家组。

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.

如果您使用MOXy,以下内容将起作用,并且可以与任何其他JAXB提供程序一起使用。此方法使用<$ c $将 java.util.Map 转换为 org.w3c.dom.Element c> XmlAdapter 。

The following will work if you are using MOXy, and should work with any other JAXB provider. This approach converts the java.util.Map to an org.w3c.dom.Element using an XmlAdapter.

MapAdapter

XmlAdapter 允许您将一个类的实例编组为另一个类的实例(请参阅: http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html )。

An XmlAdapter allows you to marshal an instance of one class as an instance of another class (see: http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html).

package forum11353790;

import java.util.*;
import java.util.Map.Entry;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.parsers.*;
import org.w3c.dom.*;

public class MapAdapter extends XmlAdapter<Element, Map<String, String>> {

    private DocumentBuilder documentBuilder;

    public MapAdapter() throws Exception {
        documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    }

    @Override
    public Element marshal(Map<String, String> map) throws Exception {
        Document document = documentBuilder.newDocument();
        Element rootElement = document.createElement("data");
        document.appendChild(rootElement);
        for(Entry<String,String> entry : map.entrySet()) {
            Element childElement = document.createElement(entry.getKey());
            childElement.setTextContent(entry.getValue());
            rootElement.appendChild(childElement);
        }
        return rootElement;
    }

    @Override
    public Map<String, String> unmarshal(Element rootElement) throws Exception {
        NodeList nodeList = rootElement.getChildNodes();
        Map<String,String> map = new HashMap<String, String>(nodeList.getLength());
        for(int x=0; x<nodeList.getLength(); x++) {
            Node node = nodeList.item(x);
            if(node.getNodeType() == Node.ELEMENT_NODE) {
                map.put(node.getNodeName(), node.getTextContent());
            }
        }
        return map;
    }

}

您指定字段/属性应通过 @XmlJavaTypeAdapter利用 XmlAdapter 注释。

You specify that a field/property should leverage the XmlAdapter via the @XmlJavaTypeAdapter annotation.

package forum11353790;

import java.io.Serializable;
import java.util.*;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlAccessorType( XmlAccessType.FIELD )
@XmlRootElement
public class Person implements Serializable {

    private String firstname;

    private String lastname;

    private List< Address > addresses = new ArrayList< Address >();

    @XmlAnyElement
    @XmlJavaTypeAdapter(MapAdapter.class)
    private Map< String, String > data = new HashMap< String, String >();

}

地址

package forum11353790;

import java.io.Serializable;
import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class Address implements Serializable {

    private String  street;
    private String  city;
    private String  state;
    private String  country;
    private String  postalcode;
    private Integer addresstype;

}

jaxb.properties

要将MOXy指定为JAXB提供程序,您需要在与域名相同的包中包含名为 jaxb.properties 的文件具有以下条目的模型(请参阅: http:// blog .bdoughan.com / 2011/05 / specify-eclipselink-moxy-as-your.html

To specify MOXy as your JAXB provider you need to include a file called jaxb.properties in the same package as your domain model with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html).

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

演示

下面是一个独立的示例,您可以运行以证明一切正常。

Below is a standalone example you can run to prove everything works.

package forum11353790;

import java.io.FileInputStream;
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>(2);
        properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
        properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
        JAXBContext jc = JAXBContext.newInstance(new Class[] {Person.class}, properties);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        StreamSource json = new StreamSource(new FileInputStream("src/forum11353790/input.json"));
        Person person = unmarshaller.unmarshal(json, Person.class).getValue();

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(person, System.out);
    }

}

input.json /输出

{
   "firstname" : "Jimmy",
   "lastname" : "Johns",
   "addresses" : [ {
      "street" : "19 Mayberry Drive",
      "city" : "Mayberry",
      "state" : "nc",
      "country" : "us",
      "postalcode" : "27043",
      "addresstype" : 1
   } ],
   "data" : {
      "sandwich" : "roast beef",
      "hair" : "brown",
      "eyes" : "blue"
   }
}

MOXy和JAX-RS / Jersey

您可以利用 MOXyJsonProvider 类在JAX-RS环境中利用MOXy:

You can leverage MOXy in a JAX-RS environment by leveraging the MOXyJsonProvider class:

  • http://blog.bdoughan.com/2012/05/moxy-as-your-jax-rs-json-provider.html

这篇关于泽西岛(哈希)地图的序列化程序使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆