有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Jersey使用的(哈希)映射的java序列化程序?

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

就在Jersey打电话给我的时候,我看到person中的地址被我正在寻找的内容(上面JSON中的内容)冲了出来。但是,我的数据元组不存在。我知道Jersey正在为Addresses调用我的no-arg构造函数,它的setter也在被调用,但我已经熬夜了,因为Jersey可能会或可能不会试图处理JSON中的这些随机(“数据”)元组。(我说“random”是因为在另一个调用中,这些可能是“cave”:“deep,dark”,“mountain”:“high,wide”,等等。这是我界面的一部分。)

为了充实我所说的,把这些POJOs视为上面的语境:

@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;
    ...

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

我需要的是Jersey中的HashMaps的某种神奇序列化程序,我似乎无法很好地解释文档,无法理解如何编写一个或解决此问题,同时仍然保持接口的灵活性

我将非常感谢任何关于如何实现这一目标的指示

罗斯贝特曼

p.S.遗憾地注意到Java.util.Map to JSON Object with Jersey / JAXB / Jackson没有帮助,尽管它显示了巨大的希望


共 (2) 个答案

  1. # 1 楼答案

    杰克逊为你提供了设施。您可以通过向Application类添加以下内容来强制执行它。注意,可能会禁用@Path注释类的自动定位

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

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

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

    MapAdapter

    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。属性

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

    输入。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: