泽西岛(哈希)地图的序列化程序使用?

Rus*_*man 6 java rest json jersey

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

{
    "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"
    }
}
Run Code Online (Sandbox Code Playgroud)

我的泽西岛代码:

@POST
public Response create( Person person )
{
    createBo( person );    <------- stopped here in debugger
    ...
Run Code Online (Sandbox Code Playgroud)

突然停摆就像新泽西打电话给我,我看到地址的人冲出来用什么我正在寻找(在JSON是头上).但是,我的数据元组不存在.我知道Jersey正在为Address es 调用我的无参数构造函数,并且它的调用者正在被调用,但是我在夜间亮起泽西可能或可能不会尝试使用这些随机("数据")元组在我的JSON中.(我说"随机",因为在不同的调用中,这些可能是"洞穴":"深,黑","山":"高,宽"等.这是我界面的一部分.)

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

@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;
    ...
Run Code Online (Sandbox Code Playgroud)

注:我不能做随机元组为我所做的地址,因为我真的不事先知道密钥是什么(而我限制地址街道,城市等).

我需要的是泽西的HashMap的某种魔术序列化器,我似乎无法很好地理解文档如何编写一个或解决这个问题,同时仍然保持我的界面的灵活性.

我将不胜感激如何实现这一目标.

拉斯贝特曼

PS遗憾地注意到带有Jersey/JAXB/Jackson的Java.util.Map到JSON对象没有帮助,尽管它显示了很大的希望.

bdo*_*han 7

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

如果您使用MOXy,以下内容将起作用,并且应该与任何其他JAXB提供程序一起使用.这种方法转换java.util.Maporg.w3c.dom.Element使用XmlAdapter.

MapAdapter

An XmlAdapter允许您将一个类的实例编组为另一个类的实例(请参阅: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;
    }

}
Run Code Online (Sandbox Code Playgroud)

您指定字段/属性应利用XmlAdaptervia @XmlJavaTypeAdapter注释.

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 >();

}
Run Code Online (Sandbox Code Playgroud)

地址

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;

}
Run Code Online (Sandbox Code Playgroud)

jaxb.properties

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

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Run Code Online (Sandbox Code Playgroud)

演示

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

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);
    }

}
Run Code Online (Sandbox Code Playgroud)

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"
   }
}
Run Code Online (Sandbox Code Playgroud)

MOXy和JAX-RS/Jersey

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