2

これは私のXml出力です

<worklist>
  <work>
    <relation-list target-type="artist">
      <relation type="composer">
        <name>Пётр Ильич Чайковский</name>
        <sort-name>Пётр Ильич Чайковский</sort-name>
      </relation>
      <relation type="writer">
        <name>Frank Turner/name>
        <sort-name>Turner Frank</sort-name>
      </relation>
    </relation-list>
  </work>
</worklist>

EclipseLInkMoxyを使用してこのjson出力を取得しようとしています

{
   "work" : [ {
       "relations" : [ {
          "type" : "composer",
          "name" : "Пётр Ильич Чайковский",
          "sort-name" : "Пётр Ильич Чайковский"
       }, {
          "type" : "writer",
          "name" : "frank turner",
          "sort-name" : "turner, frank"
       } ]
    } ]
}

しかし、私にできる最善のことは

{
   "work" : [ {
      "relationList" : [ {
         "relations" : [ {
            "type" : "composer",
             "name" : "Пётр Ильич Чайковский",
             "sort-name" : "Пётр Ильич Чайковский"
         }, { 
            "type" : "writer",
             "name" : "frank turner",
             "sort-name" : "turner, frank"

         } ]
      } ],
   } ]
}

注relationListのtarget-type属性を削除し、relationの名前をrelationsに変更しましたが、relationListをその親とマージしようとすると

<java-type name="Work">
  <java-attributes>
    <xml-element java-attribute="relationList" xml-path="."/>
  </java-attributes>
</java-type>

次の例外が発生します

Caused by: java.lang.NullPointerException
    at java.io.Writer.write(Writer.java:140)
    at org.eclipse.persistence.oxm.record.JSONWriterRecord.writeKey(JSONWriterRecord.java:580)
    at org.eclipse.persistence.oxm.record.JSONFormattedWriterRecord.openStartElement(JSONFormattedWriterRecord.java:147)
    at org.eclipse.persistence.internal.oxm.XPathNode.startElement(XPathNode.java:359)
    at org.eclipse.persistence.internal.oxm.XMLCompositeCollectionMappingNodeValue.marshalSingleValue(XMLCompositeCollectionMappingNodeValue.java:292)
    at org.eclipse.persistence.internal.oxm.XMLCompositeCollectionMappingNodeValue.marshal(XMLCompositeCollectionMappingNodeValue.java:91)
    at org.eclipse.persistence.internal.oxm.NodeValue.marshal(NodeValue.java:151)
    at org.eclipse.persistence.internal.oxm.NodeValue.marshal(NodeValue.java:104)
    at org.eclipse.persistence.internal.oxm.record.ObjectMarshalContext.marshal(ObjectMarshalContext.java:60)
    at org.eclipse.persistence.internal.oxm.XPathNode.marshal(XPathNode.java:350)
    at org.eclipse.persistence.internal.oxm.TreeObjectBuilder.buildRow(TreeObjectBuilder.java:467)
    at org.eclipse.persistence.internal.oxm.XMLCompositeCollectionMappingNodeValue.marshalSingleValue(XMLCompositeCollectionMappingNodeValue.java:299)
    at org.eclipse.persistence.internal.oxm.XMLCompositeCollectionMappingNodeValue.marshal(XMLCompositeCollectionMappingNodeValue.java:91)
    at org.eclipse.persistence.internal.oxm.NodeValue.marshal(NodeValue.java:151)
    at org.eclipse.persistence.internal.oxm.NodeValue.marshal(NodeValue.java:104)
    at org.eclipse.persistence.internal.oxm.record.ObjectMarshalContext.marshal(ObjectMarshalContext.java:60)
    at org.eclipse.persistence.internal.oxm.XPathNode.marshal(XPathNode.java:350)
    at org.eclipse.persistence.internal.oxm.TreeObjectBuilder.buildRow(TreeObjectBuilder.java:467)
    at org.eclipse.persistence.internal.oxm.XMLCompositeObjectMappingNodeValue.marshalSingleValue(XMLCompositeObjectMappingNodeValue.java:224)
    at org.eclipse.persistence.internal.oxm.XMLCompositeObjectMappingNodeValue.marshal(XMLCompositeObjectMappingNodeValue.java:144)
    at org.eclipse.persistence.internal.oxm.NodeValue.marshal(NodeValue.java:104)
    at org.eclipse.persistence.internal.oxm.record.ObjectMarshalContext.marshal(ObjectMarshalContext.java:60)
    at org.eclipse.persistence.internal.oxm.XPathNode.marshal(XPathNode.java:350)
    at org.eclipse.persistence.internal.oxm.TreeObjectBuilder.buildRow(TreeObjectBuilder.java:467)
    at org.eclipse.persistence.oxm.XMLMarshaller.marshal(XMLMarshaller.java:1074)
    at org.eclipse.persistence.oxm.XMLMarshaller.marshal(XMLMarshaller.java:689)
    at org.eclipse.persistence.oxm.XMLMarshaller.marshal(XMLMarshaller.java:602)
    at org.eclipse.persistence.jaxb.JAXBMarshaller.marshal(JAXBMarshaller.java:584)

私は問題を理解していると思います。Relation-List要素にはリレーション要素とtarget-type属性の両方が含まれているため、jsonに直接変換するには、relation-list要素で2つの要素をカプセル化する必要があります。つまり、Relation-List要素にtarget-type属性がなかった場合と思います。モデルでは問題なく動作します。

しかし、とにかくターゲットタイプを出力したくないので、それは機能するはずです、これを回避する方法はありますか?

編集: 答えてくれてありがとう、しかしそれは私が試したあなたのサンプルコードがうまくいくことを除いて私がしていることと同じように見えます。サンプルコードに要素を追加して、うまくいかないようにしました。

私の元の質問は現実よりも単純なケースを示していたので、誰かが問題を引き起こしている可能性があるものを見ることができる場合に備えて、以下に実際に完全な出力を出力しました

{
   "count" : 1,
   "offset" : 0,
   "work" : [ {
      "id" : "4ff89cf0-86af-11de-90ed-001fc6f176ff",
      "type" : "Opera",
      "score" : "100",
      "title" : "Symphony No. 5",
      "language" : "eng",
      "iswcs" : [ "T-101779304-1", "B-101779304-1" ],
      "disambiguation" : "demo",
      "aliases" : [ "Symp5" ],
      "relation-list" : [ {
         "relations" : [ {
            "type" : "composer",
            "direction" : "backward",
            "attributes" : [ "additional" ],
            "artist" : {
               "id" : "1f9df192-a621-4f54-8850-2c5373b7eac9",
               "name" : "Пётр Ильич Чайковский",
               "sort-name" : "Пётр Ильич Чайковский"
            }
         }, {
            "type" : "writer",
            "direction" : "backward",
            "artist" : {
               "id" : "abcdefgh-a621-4f54-8850-2c5373b7eac9",
               "name" : "frank",
               "sort-name" : "turner"
            }
         } ]
      } ],
      "tags" : [ {
         "count" : 10,
         "name" : "classical"
      } ]
   } ]
}

正常に動作しますが、追加します

<java-type name="Work">
    <java-attributes>
        <xml-element java-attribute="relationList" xml-path="."/>
    </java-attributes>
</java-type>

スタックトレースが発生します。

たぶん、スタックトレースは解決策を保持しています

アップデート

プロジェクト全体はオンラインで入手できます

データモデルはhttp://svn.musicbrainz.org/mmd-schema/trunk/brainz-mmd2-jaxb/ にあります。mvninstallをダウンロードして実行します。

次に、これを使用するプロジェクトはhttp://svn.musicbrainz.org/search_server/trunk/ にあります。mvnパッケージをダウンロードして実行します。

これには3つのサブプロジェクトが含まれ、問題の1つは、問題を再現するためのサーブレットプロジェクトです。

cdサーブレット

src / main / resources/oxml.xmlを編集して変更します

<xml-element java-attribute="relationList" name="relationList"/>      

<xml-element java-attribute="relationList" xml-path="."/>

mvnパッケージ

src / test / java / org / musicbrainz / search / servlet / FindWorkTestは、testOutputAsJsonNew()およびtestOutputAsJsonNewPretty()で失敗するようになりました。

さらに UpdateBlaiseは、実際には複数のrelationList要素を持つことができるという例では示されていない(そして私は気づいていなかった)問題を解決しました。つまり、Xmlは次のようになります。

<worklist>
    <work>
        <relation-list target-type="artist">
            <relation type="composer">
                <name>Jane Doe</name>
                <sort-name>Doe Jane</sort-name>
            </relation>
            <relation type="writer">
                <name>Frank Turner</name>
                <sort-name>Turner Frank</sort-name>
            </relation>
        </relation-list>
        <relation-list target-type="release">
            <relation type="cover">
                <name>Hey Jude</name>
                <sort-name>Hey Jude</sort-name>
            </relation>
        </relation-list>
    </work>
</worklist>

私が出力したいのは

{
   "work" : [ {
         "relations" : [ {
            "type" : "composer",
            "name" : "Jane Doe",
            "sort-name" : "Doe Jane"
         }, {
            "type" : "writer",
            "name" : "Frank Turner",
            "sort-name" : "Turner Frank"
         }, {
            "type" : "cover",
            "name" : "Hey Jude",
            "sort-name" : "Hey Jude"
         } ]
   } ]
}

私がそれを得ることができる最高のものに対して

{
   "work" : [ {
      "relationLists" : [ {
         "relations" : [ {
            "type" : "composer",
            "name" : "Jane Doe",
            "sort-name" : "Doe Jane"
         }, {
            "type" : "writer",
            "name" : "Frank Turner",
            "sort-name" : "Turner Frank"
         } ]
      }, {
         "relations" : [ {
            "type" : "cover",
            "name" : "Hey Jude",
            "sort-name" : "Hey Jude"
         } ]
      } ]
   } ]
}

つまり、基本的にすべてのリレーションをマージして、それらが1つのリストに含まれ、リレーションリストのラベルが失われるようにします。さまざまなリレーションのリストをマージし、各リレーションリストを識別するtarget-type属性を破棄したのは奇妙に思えるかもしれませんが、これらのサブリストを識別できる必要はありません。

これを行うことは可能ですか?

4

1 に答える 1

2

更新#2

調査の結果に基づいて、 XPathのXmlAdapter代わりに使用するようにサンプルコードを更新しました。.このアプローチは、ユースケースに非常に適しています。


更新#1

スタックトレースからは、許可されていないコレクションプロパティにself( "。")XPathを設定しているように見えます(より適切な例外がスローされるようにコードを変更します)。

Workクラスには、というコレクションプロパティがありますrelationList

@XmlElement(name = "relation-list")
protected List<RelationList> relationList;

メタデータファイルでをに設定しようとしているため、問題が発生していxml-pathます'.'

<xml-element java-attribute="relationList" xml-path="."/>

'.代わりに、コレクションを保持するオブジェクトを参照するプロパティで'パスを使用する必要があります。以下の例を参照してください。


XMLアダプター

.XPathを使用する代わりに、ユースケースは。によってより適切に処理されますXmlAdapter。AnXmlAdapterを使用すると、あるオブジェクト構造を別のオブジェクト構造に変換して、目的の入力/出力により適切にマッピングできます。このユースケースでは、は次のXmlAdapterようになります。

package forum12338288;

import java.util.*;
import javax.xml.bind.annotation.adapters.XmlAdapter;

public class WorkAdapter extends XmlAdapter<WorkAdapter.AdaptedWork, Work> {

    public static class AdaptedWork {
        public List<Relation> relations = new ArrayList<Relation>();
    }

    @Override
    public AdaptedWork marshal(Work work) throws Exception {
        AdaptedWork adaptedWork = new AdaptedWork();
        for(RelationList relationList : work.relationList) {
            for(Relation relation : relationList.relation) {
                adaptedWork.relations.add(relation);
            }
        }
        return adaptedWork;
    }

    @Override
    public Work unmarshal(AdaptedWork adaptedWork) throws Exception {
        Work work = new Work();
        RelationList relationList = new RelationList();
        for(Relation relation : adaptedWork.relations) {
            relationList.relation.add(relation);
        }
        work.relationList.add(relationList);
        return work;
    }

}

マッピングドキュメント

マッピングドキュメントは次のようになります。

oxm.xml

<?xml version="1.0"?>
<xml-bindings
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="forum12338288">
    <java-types>
        <java-type name="WorkList">
            <java-attributes>
                <xml-element java-attribute="work">
                    <xml-java-type-adapter value="forum12338288.WorkAdapter"/>
                </xml-element>
            </java-attributes>
        </java-type>
        <java-type name="RelationList">
            <java-attributes>
                <xml-transient java-attribute="targetType"/>
                <xml-element java-attribute="relation" name="relations"/>
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>

デモコード

以下のデモコードは、マッピングドキュメントを活用してXMLを読み込み、目的のJSONを出力する方法を示しています。

デモ

package forum12338288;

import java.io.File;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextProperties;

public class Demo {

    public static void main(String[] args) throws Exception {
        // XML
        JAXBContext jc = JAXBContext.newInstance(WorkList.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum12338288/input.xml");
        WorkList workList = (WorkList) unmarshaller.unmarshal(xml);

        // JSON
        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, "forum12338288/oxm.xml");
        properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
        properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
        JAXBContext jsonJC = JAXBContext.newInstance(new Class[] {WorkList.class}, properties);

        Marshaller marshaller = jsonJC.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(workList, System.out);
    }

}

input.xml

<worklist>
    <work>
        <relation-list target-type="artist">
            <relation type="composer">
                <name>Jane Doe</name>
                <sort-name>Doe Jane</sort-name>
            </relation>
            <relation type="writer">
                <name>Frank Turner</name>
                <sort-name>Turner Frank</sort-name>
            </relation>
        </relation-list>
        <relation-list target-type="release">
            <relation type="cover">
                <name>Hey Jude</name>
                <sort-name>Hey Jude</sort-name>
            </relation>
        </relation-list>
    </work>
</worklist>

出力

{
   "work" : [ {
      "relations" : [ {
         "type" : "composer",
         "name" : "Jane Doe",
         "sort-name" : "Doe Jane"
      }, {
         "type" : "writer",
         "name" : "Frank Turner",
         "sort-name" : "Turner Frank"
      }, {
         "type" : "cover",
         "name" : "Hey Jude",
         "sort-name" : "Hey Jude"
      } ]
   } ]
}

JAVAモデル

以下は、すべてが機能することを確認するために使用したJavaモデルです。

WorkList

package forum12338288;

import java.util.List;
import javax.xml.bind.annotation.*;

@XmlRootElement(name="worklist")
@XmlAccessorType(XmlAccessType.FIELD)
public class WorkList {

    List<Work> work;

}

仕事

package forum12338288;

import java.util.*;

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class Work {

    @XmlElement(name="relation-list")
    List<RelationList> relationList = new ArrayList<RelationList>();

}

RelationList

package forum12338288;

import java.util.List;

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class RelationList {

    @XmlAttribute(name="target-type")
    String targetType;

    List<Relation> relation;

}

関係

package forum12338288;

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class Relation {

    @XmlAttribute
    String type;

    String name;

    @XmlElement(name="sort-name")
    String sortName;

}

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
于 2012-09-10T11:57:30.967 に答える