【问题标题】:Serializer for (Hash)Maps for Jersey use?用于泽西岛的(哈希)映射的序列化器?
【发布时间】:2012-07-06 09:58:57
【问题描述】:

我正在尝试将以下负载发布到基于 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"
    }
}

我的球衣代码:

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

就在泽西打电话给我的时候停止了,我看到 person 中的地址完全被我正在寻找的内容(上面的 JSON 中的内容)冲掉了。但是,我的数据元组不存在。我知道 Jersey 正在为 Address 调用我的无参数构造函数,并且它的设置器被调用,但我在夜间起床,至于 Jersey 可能会或可能不会尝试处理这些我的 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;
    ...

注意:我不能像我所做的那样做随机元组 Address 因为我实际上事先并不知道键是什么(而我限制了 Address街道城市等)。

我需要一种用于泽西岛 HashMap 的魔法序列化程序,我似乎无法很好地解释文档以理解如何编写一个或解决这个问题,同时仍保持灵活性我的界面。

我将不胜感激有关如何完成此操作的任何指示。

拉斯贝特曼

附:遗憾的是,Java.util.Map to JSON Object with Jersey / JAXB / Jackson 并没有帮助,尽管它显示出巨大的希望。

【问题讨论】:

    标签: java json rest jersey


    【解决方案1】:

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

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

    地图适配器

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

    人物

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

    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/specifying-eclipselink-moxy-as-your.html)。

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

    演示

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

    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/Output

    {
       "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:

    【讨论】:

    • 感谢您快速而令人印象深刻的回答。我正在试用你的演示。我似乎无法处理包含 org.eclipse.persistence.jaxb.JAXBContextProperties 的 JAR。我需要吞下整个 MOXy/EclipseLink 下载,还是我可以只吃一个 JAR(或几个)?
    • @RussBateman - 您需要一个 EclipseLink 2.4.0 安装程序或来自eclipse.org/eclipselink/downloads 的捆绑包。如果你熟悉 Maven,你可以做类似的事情:github.com/bdoughan/blog20120418/blob/master/pom.xml
    • 简而言之,到目前为止,我已经在 EclipseLink 中对这个符号的所有源代码和 JAR 文件进行了 grep 和 jar tf 处理,但无济于事。 (我不做 Maven。)我下载了 EclipseLink 2.1.0(因为我使用的是 Helios 而不是 Juno——这有什么不同吗?)。此外,如前所述,项目限制使得很难走完整的框架路线。再一次,我必须吞下所有的 EclipseLink 还是我可以挑选这个功能?我可以走这条路看到这个解决方案,但如果我不能挑选,我将不得不找到另一个解决方案。谢谢(对这里的跛脚感到抱歉)。
    • @RussBateman - 您需要安装 EclipseLink 2.4。您可以使用 eclipselink.jar(所有 EclipseLink)或以下包:core、moxy、antlr 和 asm。
    • 我已将 EclipseLink 添加到我活跃的 Eclipse 论坛中,但我已成功地将这个解决方案集成到我的 Jersey ReST 服务器应用程序中。它工作得很好,完全符合我挑选樱桃的要求。布莱斯,我非常感谢你的解决方案!
    【解决方案2】:

    Jackson 为您提供便利。您可以通过将以下内容添加到您的 Application 类来强制它。请注意,这可能禁用自动定位您的 @Path 注释类。

    @Override
    public Set<Object> getSingletons() {
        return ImmutableSet
                .<Object> builder()
                .add(new JacksonJaxbJsonProvider(new ObjectMapper(),
                        JacksonJaxbJsonProvider.DEFAULT_ANNOTATIONS)).build();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-06
      • 1970-01-01
      • 2011-08-02
      • 1970-01-01
      • 2016-10-18
      • 1970-01-01
      相关资源
      最近更新 更多