1概要

このチュートリアルでは、http://cxf.apache.org/docs/aegis-21.html[Aegis]データバインディング、つまりJavaオブジェクトとXMLスキーマで記述されたXML文書との間のマッピングが可能なサブシステムについて紹介します。 Aegisでは、プログラミング作業を最小限に抑えながら、マッピングプロセスを詳細に制御できます。

Aegisはhttp://cxf.apache.org/[Apache CXF]の一部ですが、このフレームワーク内でのみ使用されることを制限されていません。代わりに、このデータバインディングメカニズムはどこでも使用できるので、このチュートリアルでは独立したサブシステムとしての使用法に焦点を当てます。


2 Mavenの依存関係

Aegisデータバインディングをアクティブにするために必要な唯一の依存関係は次のとおりです。

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-databinding-aegis</artifactId>
    <version>3.1.8</version>
</dependency>

このアーティファクトの最新バージョンはhttps://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22org.apache.cxf%22%20AND%20a%3A%22cxf-rt-にあります。 databinding-aegis%22[ここ]。


3型の定義

このセクションでは、Aegisを説明するために使用される3つのタイプの定義について説明します。


3.1.

コース


これは、この例では最も単純なクラスで、次のように定義されています。

public class Course {
    private int id;
    private String name;
    private String instructor;
    private Date enrolmentDate;

   //standard getters and setters
}


3.2.

CourseRepo



CourseRepo

は、このモデルの最上位タイプです。カスタムアダプタなしではJAXBでは不可能な、Javaインタフェースの整列化がどれほど簡単かを示すために、クラスではなくインタフェースとして定義します。

public interface CourseRepo {
    String getGreeting();
    void setGreeting(String greeting);
    Map<Integer, Course> getCourses();
    void setCourses(Map<Integer, Course> courses);
    void addCourse(Course course);
}


getCourses

メソッドは戻り型

Map

で宣言していることに注意してください。

これは、JAXBに対するAegisのもう1つの利点を表すためのものです。前者はカスタムアダプタなしでマップをマーシャリングすることはできません。


3.3.

CourseRepoImpl


このクラスは

CourseRepo

インターフェースへの実装を提供します。

public class CourseRepoImpl implements CourseRepo {
    private String greeting;
    private Map<Integer, Course> courses = new HashMap<>();

   //standard getters and setters

    @Override
    public void addCourse(Course course) {
        courses.put(course.getId(), course);
    }
}


4カスタムデータバインディング

カスタマイズを有効にするには、XMLマッピングファイルがクラスパスに存在する必要があります。これらのファイルは、関連するJava型のパッケージ階層に対応する構造を持つディレクトリに配置する必要があります。

たとえば、完全修飾名クラスの名前が

package.ClassName

の場合、その関連マッピングファイルはクラスパスの

package/ClassName

サブディレクトリ内になければなりません。マッピングファイルの名前は、

.aegis.xml

サフィックスが追加された、関連付けられたJava型と同じである必要があります。


4.1.

CourseRepo

マッピング


CourseRepo

インターフェースは

com.baeldung.cxf.aegis

パッケージに属しているため、対応するマッピングファイルは

CourseRepo.aegis.xml

という名前でクラスパスの

com/baeldung/cxf/aegis

ディレクトリに配置されます。


CourseRepo

マッピングファイルでは、

CourseRepo

インタフェースに関連付けられているXML要素の名前と名前空間、およびその

greeting

プロパティのスタイルを変更します。

<mappings xmlns:ns="http://courserepo.baeldung.com">
    <mapping name="ns:Baeldung">
        <property name="greeting" style="attribute"/>
    </mapping>
</mappings>


4.2. コースマッピング


CourseRepo

タイプと同様に、クラス

Course

のマッピングファイルは

Course.aegis.xml

という名前であり、

com/baeldung/cxf/aegis

ディレクトリにもあります。

このマッピングファイルでは、マーシャリング時に

Course

クラスの

instructor

プロパティを無視するようにAegisに指示しているので、その値は出力XMLドキュメントから再作成されたオブジェクトでは使用できません。

<mappings>
    <mapping>
        <property name="instructor" ignore="true"/>
    </mapping>
</mappings>


Aegisのホームページ

は、私たちがより多くのカスタマイズオプションを見つけることができるところです。


5テスト中

このセクションは、Aegisデータバインディングの使用法を説明するテストケースを設定および実行するためのステップバイステップガイドです。

テストプロセスを容易にするために、テストクラス内に2つのフィールドを宣言します。

public class BaeldungTest {
    private AegisContext context;
    private String fileName = "baeldung.xml";

   //other methods
}

これらのフィールドは、このクラスの他のメソッドで使用されるようにここで定義されています。


5.1.

AegisContext

初期化

まず、

AegisContext

オブジェクトを作成する必要があります。

context = new AegisContext();

その

AegisContext

インスタンスが設定され初期化されます。コンテキストにルートクラスを設定する方法は次のとおりです。

Set<Type> rootClasses = new HashSet<Type>();
rootClasses.add(CourseRepo.class);
context.setRootClasses(rootClasses);

Aegisは、

Set <Type>

オブジェクト内の各

Type

に対してXMLマッピング要素を作成します。このチュートリアルでは、

CourseRepo

のみをルートタイプとして設定します。

それでは、コンテキストの実装マップを設定して、

CourseRepo

インターフェースのプロキシクラスを指定しましょう。

Map<Class<?>, String> beanImplementationMap = new HashMap<>();
beanImplementationMap.put(CourseRepoImpl.class, "CourseRepo");
context.setBeanImplementationMap(beanImplementationMap);

Aegisコンテキストの最後の設定は、対応するXML文書に

xsi:type

属性を設定するように指示することです。この属性は、マッピングファイルで上書きされない限り、関連付けられているJavaオブジェクトの実際の型名を保持します。

context.setWriteXsiTypes(true);


AegisContext

インスタンスが初期化される準備が整いました。

context.initialize();

コードをきれいに保つために、このサブセクションのすべてのコードスニペットを1つのヘルパーメソッドにまとめます。

private void initializeContext() {
   //...
}


5.2. 簡単なデータ設定

このチュートリアルは単純なので、永続的なソリューションに頼るのではなく、メモリ内でサンプルデータを生成します。以下のセットアップロジックを使用してコースリポジトリにデータを入力しましょう。

private CourseRepoImpl initCourseRepo() {
    Course restCourse = new Course();
    restCourse.setId(1);
    restCourse.setName("REST with Spring");
    restCourse.setInstructor("Eugen");
    restCourse.setEnrolmentDate(new Date(1234567890000L));

    Course securityCourse = new Course();
    securityCourse.setId(2);
    securityCourse.setName("Learn Spring Security");
    securityCourse.setInstructor("Eugen");
    securityCourse.setEnrolmentDate(new Date(1456789000000L));

    CourseRepoImpl courseRepo = new CourseRepoImpl();
    courseRepo.setGreeting("Welcome to Beldung!");
    courseRepo.addCourse(restCourse);
    courseRepo.addCourse(securityCourse);
    return courseRepo;
}


5.3. JavaオブジェクトとXML要素のバインド

JavaオブジェクトをXML要素に整列化するために必要な手順は、次のヘルパーメソッドで説明されています。

private void marshalCourseRepo(CourseRepo courseRepo) throws Exception {
    AegisWriter<XMLStreamWriter> writer = context.createXMLStreamWriter();
    AegisType aegisType = context.getTypeMapping().getType(CourseRepo.class);
    XMLStreamWriter xmlWriter = XMLOutputFactory.newInstance()
      .createXMLStreamWriter(new FileOutputStream(fileName));

    writer.write(courseRepo,
      new QName("http://aegis.cxf.baeldung.com", "baeldung"), false, xmlWriter, aegisType);

    xmlWriter.close();
}

ご覧のとおり、

AegisWriter

および

AegisType

オブジェクトは

AegisContext

インスタンスから作成する必要があります。

AegisWriter

オブジェクトは、指定されたJavaインスタンスを指定された出力に整列化します。

この場合、これはファイルシステムの

fileName

クラスレベルフィールドの値にちなんで名付けられたファイルに関連付けられた

XMLStreamWriter

オブジェクトです。

次のメソッドは、XMLドキュメントを特定の型のJavaオブジェクトに非整列化します。

private CourseRepo unmarshalCourseRepo() throws Exception {
    AegisReader<XMLStreamReader> reader = context.createXMLStreamReader();
    XMLStreamReader xmlReader = XMLInputFactory.newInstance()
      .createXMLStreamReader(new FileInputStream(fileName));

    CourseRepo courseRepo = (CourseRepo) reader.read(
      xmlReader, context.getTypeMapping().getType(CourseRepo.class));

    xmlReader.close();
    return courseRepo;
}

ここでは、

AegisRetext

オブジェクトが

AegisContext

インスタンスから生成されています。

AegisReader

オブジェクトは、提供された入力からJavaオブジェクトを作成します。この例では、その入力は、上記の

marshalCourseRepo

メソッドで生成したファイルを基にした

XMLStreamReader

オブジェクトです。


5.4. アサーション

それでは、前のサブセクションで定義したすべてのヘルパーメソッドをテストメソッドにまとめましょう。

@Test
public void whenMarshalingAndUnmarshalingCourseRepo__thenCorrect()
  throws Exception {
    initializeContext();
    CourseRepo inputRepo = initCourseRepo();
    marshalCourseRepo(inputRepo);
    CourseRepo outputRepo = unmarshalCourseRepo();
    Course restCourse = outputRepo.getCourses().get(1);
    Course securityCourse = outputRepo.getCourses().get(2);

   //JUnit assertions
}

最初に

CourseRepo

インスタンスを作成し、次にそれをXML文書に整列化し、最後にその文書を非整列化して元のオブジェクトを再作成します。再作成したオブジェクトが期待どおりであることを確認しましょう。

assertEquals("Welcome to Beldung!", outputRepo.getGreeting());
assertEquals("REST with Spring", restCourse.getName());
assertEquals(new Date(1234567890000L), restCourse.getEnrolmentDate());
assertNull(restCourse.getInstructor());
assertEquals("Learn Spring Security", securityCourse.getName());
assertEquals(new Date(1456789000000L), securityCourse.getEnrolmentDate());
assertNull(securityCourse.getInstructor());


instructor

プロパティを除いて、

Date

型の値を持つ

enrolmentDate

プロパティも含めて、他のすべての値で値が復元されることは明らかです。

Course

オブジェクトを整列化するときにAinsが

instructor

プロパティを無視するように指示したので、これはまさに私たちが期待していることです。


5.5. 出力XMLドキュメント

Aegisマッピングファイルの効果を明確にするために、カスタマイズなしのXML文書を以下に示します。

<ns1:baeldung xmlns:ns1="http://aegis.cxf.baeldung.com"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:type="ns1:CourseRepo">
    <ns1:courses>
        <ns2:entry xmlns:ns2="urn:org.apache.cxf.aegis.types">
            <ns2:key>1</ns2:key>
            <ns2:value xsi:type="ns1:Course">
                <ns1:enrolmentDate>2009-02-14T06:31:30+07:00
                </ns1:enrolmentDate>
                <ns1:id>1</ns1:id>
                <ns1:instructor>Eugen</ns1:instructor>
                <ns1:name>REST with Spring</ns1:name>
            </ns2:value>
        </ns2:entry>
        <ns2:entry xmlns:ns2="urn:org.apache.cxf.aegis.types">
            <ns2:key>2</ns2:key>
            <ns2:value xsi:type="ns1:Course">
                <ns1:enrolmentDate>2016-03-01T06:36:40+07:00
                </ns1:enrolmentDate>
                <ns1:id>2</ns1:id>
                <ns1:instructor>Eugen</ns1:instructor>
                <ns1:name>Learn Spring Security</ns1:name>
            </ns2:value>
        </ns2:entry>
    </ns1:courses>
    <ns1:greeting>Welcome to Beldung!</ns1:greeting>
</ns1:baeldung>

これをAegisカスタムマッピングが動作している場合と比較してください。

<ns1:baeldung xmlns:ns1="http://aegis.cxf.baeldung.com"
    xmlns:ns="http://courserepo.baeldung.com"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:type="ns:Baeldung" greeting="Welcome to Beldung!">
    <ns:courses>
        <ns2:entry xmlns:ns2="urn:org.apache.cxf.aegis.types">
            <ns2:key>1</ns2:key>
            <ns2:value xsi:type="ns1:Course">
                <ns1:enrolmentDate>2009-02-14T06:31:30+07:00
                </ns1:enrolmentDate>
                <ns1:id>1</ns1:id>
                <ns1:name>REST with Spring</ns1:name>
            </ns2:value>
        </ns2:entry>
        <ns2:entry xmlns:ns2="urn:org.apache.cxf.aegis.types">
            <ns2:key>2</ns2:key>
            <ns2:value xsi:type="ns1:Course">
                <ns1:enrolmentDate>2016-03-01T06:36:40+07:00
                </ns1:enrolmentDate>
                <ns1:id>2</ns1:id>
                <ns1:name>Learn Spring Security</ns1:name>
            </ns2:value>
        </ns2:entry>
    </ns:courses>
</ns1:baeldung>

このセクションで定義したテストを実行した後、このXML構造はプロジェクトのメインディレクトリのすぐ下の

baeldung.xml

にあります。


CourseRepo

オブジェクトに対応するXML要素の

type

属性と名前空間が、

CourseRepo.aegis.xml

ファイルに設定した内容に従って変わることがわかります。

greeting

プロパティも属性に変換され、

Course

オブジェクトの

instructor

プロパティは予想通りに消えます。

デフォルトでは、Aegisは基本的なJavaの型を最もよく一致するスキーマの型に変換します。このチュートリアルに示すように、

Date

オブジェクトから

xsd:dateTime

要素まで。ただし、対応するマッピングファイルに設定を設定することで、その特定のバインディングを変更できます。

詳細については、http://cxf.apache.org/docs/aegis-21.html[Aegis home page]を参照してください。


6. 結論

このチュートリアルでは、Apache CXF Aegisデータバインディングをスタンドアロンサブシステムとして使用する方法を説明します。 Aegisを使用してJavaオブジェクトをXML要素にマッピングする方法、およびその逆の方法を示します。

このチュートリアルでは、データバインディング動作をカスタマイズする方法にも焦点を当てています。

そして、いつものように、これらすべての例とコードスニペットの実装はhttps://github.com/eugenp/tutorials/tree/master/apache-cxf[the GitHub project]にあります。