自定义解组(在Jersey中)请求体中的字段变为HashMap?

时间:2015-11-06 20:24:40

标签: java web-services jersey unmarshalling

我有一个Jersey(1.18.1)服务器,目前期望在POST请求中说Person

<person>
    <name>sdfsdfd</name>
    <age>24</age>
    ...
</person>

上面的请求体被反序列化为我的服务器方法上的Person类(比如/add

我需要在请求中添加options成员,使其成为可选项,但在传递时应该序列化为Map<String, String>类中的Person成员:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
@XmlRootElement(name = "person")
class Person {
    @XmlElement(required = true)
    private String name;

    @XmlElement(required = true)
    private int age;

    @XmlElement(required = false)
    private Map<String, String> options;

    // ctor, getters, setters etc.
}

我知道我必须编写一个自定义反序列化器,如@XmlJavaTypeAdapter(PersonOptionsAdapter.class).我在网上找到的有关适配器的内容是在整个请求体需要自定义解组时使用。但是,对于特定成员而言,这似乎对我没有用。我尝试使用options注释PersonOptionsAdapter成员,以及类似的一些内容。

请分享您对如何在请求对象的特定成员上应用自定义适配器的想法和/或解决方案?

1 个答案:

答案 0 :(得分:0)

我找到了一种方法......

这是JAXB适配器

<!-- language: java -->
@XmlRootElement
public class JaxbXml2MapAdapter extends XmlAdapter<Object, HashMap<String, String>> {

    public JaxbXml2MapAdapter() {
        super();
    }

    @Override
    public Object marshal(HashMap<String, String> map) throws Exception {
        // I wasn't using it for sending this out in the response. So
        // did not bother to implement marshaling.
        return null;
    }

    @Override
    public HashMap<String, String> unmarshal(Object rawRoot) throws Exception {
        final HashMap<String, String> map = new HashMap<String, String>();

        if (rawRoot == null || !(rawRoot instanceof Element)) {
            return map;
        }

        final Element  root     = (Element) rawRoot;
        final NodeList children = root.getChildNodes();

        if (children.getLength() == 0) {
            return map;
        }

        // TODO: Analyze if there is a better way of reading the nodes.
        // Currently we get null/empty node names, white space values etc.

        for (int index = 0; index < children.getLength(); ++index) {
            final Node   child = children.item(index);
            final String name  = child.getLocalName();

            if (name == null || name.length == 0) {
               continue;
            }

            final String value = child.getTextContent();
            map.put(name, value);
        }

        return map;
    }
}

以下是如何使用适配器:

<!-- language: java -->
@XmlRootElement(name = "myRequest")
public class MyRequest {

    @XmlElement(required = true)
    private String token;

    private List<int> flags = new ArrayList<int>();

    @XmlJavaTypeAdapter(value = JaxbXml2MapAdapter.class)
    private HashMap<String, String> options = new HashMap<String, String>();

    public MyRequest() {
    }

    // .... blah blah blah
}

以下是示例请求正文(是可选参数):

<!-- language: xml -->
<myRequest>
   <token>QWe35234</token>
   <flags>1</flags>
   <flags>4</flags>
   <options>
       <name>Johnny</name>
       <points>25.3</options>
       <someRandomStuff>sdfsgsagasfgasgsaf</someRandomStuff>
   </options>
</myRequest>

希望有所帮助