6

次のペイロードをJerseyベースのWebサービスにPOSTしようとしています:

{
    "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 から電話がかかってきたときに電話を切ったところ、私が探しているもの (上記の JSON にあるもの) とまったく同じアドレスがフラッシュされているのが見えましたしかし、私のデータタプルはありません。Jersey がAddress esの引数なしのコンストラクターを呼び出しており、そのセッターが呼び出されていることは知っていますが、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で行ったようにランダムなタプルを実行することはできません。これは、キーがどうなるかを実際には事前に知らないためです (一方、Addressstreetcityなどに制限しています)。

私が必要としているのは、Jersey のHashMap s用の何らかの魔法のシ​​リアライザーであり、インターフェイスの柔軟性を維持しながら、ドキュメントを作成する方法やこの問題を回避する方法を理解するのに十分なほどドキュメントを解釈できないようです。

これを達成する方法についての指示をいただければ幸いです。

ラス・ベイトマン

PS 残念ながら、Jersey / JAXB / Jackson を使用した Java.util.Map to JSON Object は役に立たなかったことに注意してください。

4

2 に答える 2

7

注: 私はEclipseLink JAXB(MOXy)のリーダーであり、JAXB(JSR-222)エキスパートグループのメンバーです。

以下は、MOXyを使用している場合に機能し、他のJAXBプロバイダーと連携する必要があります。java.util.Mapこのアプローチは、org.w3c.dom.Elementを使用してに変換しXmlAdapterます。

MapAdapter

AnXmlAdapterを使用すると、あるクラスのインスタンスを別のクラスのインスタンスとしてマーシャリングできます(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;
    }

}

フィールド/プロパティがアノテーションXmlAdapterを介してを活用する必要があることを指定します。@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 >();

}

住所

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を活用できます。

于 2012-07-06T10:47:18.577 に答える
0

ジャクソンはあなたに施設を提供します。クラスに以下を追加することで強制できますApplication。これにより、注釈付きクラスの自動ロケーションが無効になる場合があることに注意してください。@Path

@Override
public Set<Object> getSingletons() {
    return ImmutableSet
            .<Object> builder()
            .add(new JacksonJaxbJsonProvider(new ObjectMapper(),
                    JacksonJaxbJsonProvider.DEFAULT_ANNOTATIONS)).build();
}
于 2014-10-05T06:03:27.930 に答える