1. 概要

このチュートリアルでは、 Aegis データバインディングの概要を説明します。これは、JavaオブジェクトとXMLスキーマで記述されたXMLドキュメントの間でマッピングできるサブシステムです。 Aegisを使用すると、プログラミングの労力を最小限に抑えながら、マッピングプロセスを詳細に制御できます。

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

2. Mavenの依存関係

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

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

このアーティファクトの最新バージョンはここにあります。

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 は、モデルの最上位タイプです。 これをクラスではなくインターフェースとして定義し、Javaインターフェースのマーシャリングがいかに簡単であるかを示します。これは、カスタムアダプターがないとJAXBでは不可能です。

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の別の利点を表現することを目的としています。 後者はカスタムアダプタなしでマップをマーシャリングすることはできませんが、前者はマーシャリングできます。

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 であり、[クラスパス上のX180X]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はそれぞれの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;
}

ここで、AegisReaderオブジェクトは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 オブジェクトをマーシャリングするときに、 instructor プロパティを無視するようにAegisに指示したため、まさに私たちが期待していることです。

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要素へ。 ただし、対応するマッピングファイルで構成を設定することにより、その特定のバインディングを変更できます。

詳細については、Aegisホームページにアクセスしてください。

6. 結論

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

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

そして、いつものように、これらすべての例とコードスニペットの実装は、GitHubプロジェクトにあります。