9. XMLによるマッピング方法
アノテーションだけではなく、外部XMLファイルでマッピングができます。
これはダイナミック・アノテーションという、アノテーションと同様の情報をXMLファイルで定義します。
以下にクラスに対してアノテーションを付与するXMLファイルの例を示します。
1<?xml version="1.0" encoding="utf-8"?>
2<annotations>
3 <class name="com.gh.mygreen.xlsmapper.example.SheetObject">
4 <annotation name="com.gh.mygreen.xlsmapper.annotation.XlsSheet">
5 <attribute name="name">'Users'</attribute>
6 </annotation>
7 </class>
8</annotations>
アノテーションの属性値の指定にはOGNL式を使用します。メソッドにアノテーションを付与する場合は次のようになります。
1<?xml version="1.0" encoding="utf-8"?>
2<annotations>
3 <class name="com.gh.mygreen.xlsmapper.example.SheetObject">
4 <annotation name="com.gh.mygreen.xlsmapper.annotation.XlsSheet">
5 <attribute name="name">'Users'</attribute>
6 </annotation>
7 <method name="setTitle">
8 <annotation name="com.gh.mygreen.xlsmapper.annotation.XlsLabelledCell">
9 <attribute name="label">'Title'</attribute>
10 <attribute name="type">@com.gh.mygreen.xlsmapper.annotation.XlsLabelledCellType@Right</attribute>
11 </annotation>
12 </method>
13 </class>
14</annotations>
フィールドにアノテーションを付与できます。
1<?xml version="1.0" encoding="utf-8"?>
2<annotations>
3 <class name="com.gh.mygreen.xlsmapper.example.SheetObject">
4 <field name="title">
5 <annotation name="...">
6 ...
7 </annotation>
8 </field>
9 </class>
10</annotations>
外部XMLファイルを使う場合、ハードコードされたアノテーションを外部XMLファイルの内容でオーバーライドできます。
XML情報は AnnotationMappingInfo
として読み込み、 Configuration#setAnnotationMapping(..)
メソッドに渡します。
1// XMLファイルに定義したマッピング情報の読み込み
2AnnotationMappingInfo annotaionMapping = XmlIO.load(new File("example.xml"), "UTF-8");
3
4// システム情報に設定
5XlsMapper xlsMapper = new XlsMapper();
6xlsMapper.getConfiguration.setAnnotationMapping(annotaionMapping);
7
8// マッピング
9SheetObject sheet = xlsMapper.load(new FileInputStream("example.xls"), SheetObject.class);
ClassやMethod、Fieldオブジェクトから直接アノテーションを取得する代わりに AnnotationReader
を使えば、XMLで宣言されたアノテーションと、クラスに埋め込まれているアノテーションを区別せずに取得できます。
AnnotationReader
にはこの他にもメソッド、フィールドに付与されたアノテーションを取得するためのメソッドも用意されています。
9.1. アノテーションをXMLで上書きする場合
XMLに定義していないメソッドなどは、Javaのソースコードの定義が有効になります。 しかし、XMLにメソッドを定義すると、そのメソッドに対してはXMLの定義が優先されます。
例えば、1つのメソッドにアノテーションを3つ定義していた場合、1つのアノテーションの定義を変更したい場合でも、XMLでは3つのアノテーションの定義を行う必要があります。
このように、一部のアノテーションのみを書き換えたい場合、属性 override=true
を付与すると、差分が反映されます。
注釈
属性
override
は、ver1.0から有効です。属性
override=true
の場合は、Javaのソースコードの定義に定義している一部のアノテーションを書き換えるために利用します。Javaのソースコード側の定義を削除する場合は、従来通り、属性
override
を定義しない、またはorverride=false
を定義し、必要なアノテーションの定義をします。
1<?xml version="1.0" encoding="UTF-8"?>
2<annotations>
3
4 <!-- クラスに定義したアノテーションを上書きする場合 -->
5 <class name="com.gh.mygreen.xlsmapper.example.SheetObject" override="true">
6 <annotation name="com.gh.mygreen.xlsmapper.annotation.XlsSheet">
7 <attribute name="name">''</attribute>
8 <attribute name="regex">'リスト.+'</attribute>
9 </annotation>
10
11 <!-- フィールドに定義したアノテーションを一部、上書きする場合 -->
12 <field name="name" override="true">
13 <annotation name="com.gh.mygreen.xlsmapper.annotation.XlsLabelledCell">
14 <attribute name="label">'クラス名'</attribute>
15 <attribute name="type">@com.gh.mygreen.xlsmapper.annotation.LabelledCellType@Bottom</attribute>
16 </annotation>
17 </field>
18
19 <!-- メソッドに定義したアノテーションを一部、上書きする場合 -->
20 <method name="setRecords" override="true">
21 <annotation name="com.gh.mygreen.xlsmapper.annotation.XlsHorizontalRecords">
22 <attribute name="tableLabel">'名簿一覧'</attribute>
23 <attribute name="terminal">@com.gh.mygreen.xlsmapper.annotation.RecordTerminal@Border</attribute>
24 </annotation>
25 </method>
26
27 </class>
28
29</annotations>
1@XlsSheet(name="テスト") // <== 上書きされる
2private static class SheetObject {
3
4 @XlsSheetName
5 private String sheetName;
6
7 @XlsOrder(1)
8 @XlsTrim
9 @XlsLabelledCell(label="名称", type=LabelledCellType.Right) // <== 上書きされる
10 private String name;
11
12 private List<NormalRecord> records;
13
14 public List<NormalRecord> getRecords() {
15 return records;
16 }
17
18 @XlsOrder(2)
19 @XlsHorizontalRecords(tableLabel="クラス名", terminal=RecordTerminal.Empty) // <== 上書きされる
20 public void setRecords(List<NormalRecord> records) {
21 this.records = records;
22 }
23
24}
9.2. XMLを動的に組み立てる場合
アノテーション用のXMLを記述する際に、クラス名やアノテーション名は、FQCN(完全修飾クラス名)で記述する必要があり、間違えることがあります。
また、アノテーションの値はOGNL形式で記述する必要があるため、書式を知らない場合はわざわざ調べる必要があります。
このような時は、XMLをJavaにて動的に組み立てる方法を取ることができます。
XMLを動的に組み立てるには、 各XMLのオブジェクトのビルダクラスである XmlInfo.Builder
などを利用します。
さらに、ヘルパクラスである com.gh.mygreen.xlsmapper.xml.XmlBuilder
を利用すると、より直感的に作成できます。
XmlBuilderを、static import するとより使い安くなります。
AnnotationMappingInfoオブジェクトは、
com.gh.mygreen.xlsmapper.xml.XmlIO#save(...)
メソッドでファイルに保存します。作成した XmlInfoオブジェクトは、JAXBのアノテーションが付与されているため、 JAXBの機能を使ってXMLに変換 することもできます。
アノテーションの属性値は、
AttributeInfo.Builder#attribute(...)
メソッドで自動的にOGNLの書式に変換されます。OGNL式に変換するクラスは、
com.gh.mygreen.xlsmapper.xml.OgnlValueFormatter
クラスで処理されます。独自にカスタマイズしたクラスで処理したい場合は、予め
XmlBuilder#setValueFormatter(...)
メソッドで変更することが可能です。直接OGNLの値を設定したい場合は、
AttributeInfo.Builder#attributeWithNative(...)
メソッドで設定することもできます。
注釈
XmlBuilderクラスなどの、XMLを動的に組み立てる機能は、ver.1.1から追加されたものです。
1// XmlBuilder.createXXX() メソッドを簡単に呼ぶために、static import します。
2import static com.gh.mygreen.xlsmapper.xml.XmlBuilder.*;
3
4public void sample() {
5
6 AnnotationMappingInfo annotationMapping = createXml() // ルートオブジェクトのXmlInfo(<annotations>タグ)を組み立てるビルダクラスを作成します。
7 .classInfo(createClass(SimpleSheet.class) // クラス「SimpleSheet」に対するXML情報の組み立てを開始します。
8 .annotation(createAnnotation(XlsSheet.class) // クラスのアノテーション「@XlsSheet」情報の組み立てを開始します。
9 .attribute("name", "単純なシート") // アノテーションの属性「name」を設定します。自動的にOGNL形式に変換されます。
10 .buildAnnotation()) // 組み立てたアノテーション情報のオブジェクトを取得します。
11 .field(createField("sheetName") // フィールド「sheetName」情報の組み立てを開始します。
12 .annotation(createAnnotation(XlsSheetName.class) // フィールドのアノテーション「@XlsSheetName」情報の組み立てを開始します。
13 .buildAnnotation())
14 .buildField()) // 組み立てたフィールド情報のオブジェクトを取得します。
15 .field(createField("name")
16 .annotation(createAnnotation(XlsLabelledCell.class)
17 .attribute("label", "名称")
18 .attributeWithNative("type", "@com.gh.mygreen.xlsmapper.annotation.LabelledCellType@Right") // 直接OGNL式で設定することもできます。
19 .buildAnnotation())
20 .annotation(createAnnotation(XlsTrim.class)
21 .buildAnnotation())
22 .annotation(createAnnotation(XlsDefaultValue.class)
23 .attribute("value", "-")
24 .buildAnnotation())
25 .buildField())
26 .method(createMethod("setRecords") // メソッド「setRecords」情報の組み立てを開始します。
27 .annotation(createAnnotation(XlsHorizontalRecords.class) // メソッドのアノテーションを設定します。
28 .attribute("tableLabel", "名簿一覧")
29 .attribute("terminal", RecordTerminal.Border)
30 .buildAnnotation())
31 .buildMethod()) // 組み立てたメソッド情報のオブジェクトを取得します。
32 .buildClass()) // 組み立てたクラス情報のオブジェクトを取得します。
33 .buildXml(); // 組み立てたXML情報のオブジェクトを取得します。
34
35 // XMLをファイルに保存します。
36 XmlIO.save(annotationMapping, new File("anno_simple.xml"), "UTF-8");
37
38}
組み立てたXMLは、下記のようになります。
1<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2<annotations>
3 <class name="com.gh.mygreen.xlsmapper.example.SimpleSheet" override="false">
4 <annotation name="com.gh.mygreen.xlsmapper.annotation.XlsSheet">
5 <attribute name="name">"単純なシート"</attribute>
6 </annotation>
7 <field name="sheetName" override="false">
8 <annotation name="com.gh.mygreen.xlsmapper.annotation.XlsSheetName"/>
9 </field>
10 <field name="name" override="false">
11 <annotation name="com.gh.mygreen.xlsmapper.annotation.XlsLabelledCell">
12 <attribute name="label">"名称"</attribute>
13 <attribute name="type">@com.gh.mygreen.xlsmapper.annotation.LabelledCellType@Right</attribute>
14 </annotation>
15 <annotation name="com.gh.mygreen.xlsmapper.annotation.XlsTrim" />
16 <annotation name="com.gh.mygreen.xlsmapper.annotation.XlsDefaultValue">
17 <attribute name="value">"-"</attribute>
18 </annotation>
19 </field>
20 <method name="setRecords" override="false">
21 <annotation name="com.gh.mygreen.xlsmapper.annotation.XlsHorizontalRecords">
22 <attribute name="tableLabel">"名簿一覧"</attribute>
23 <attribute name="terminal">@com.gh.mygreen.xlsmapper.annotation.RecordTerminal@Border</attribute>
24 </annotation>
25 </method>
26 </class>
27</annotations>
XMLに変換しないで、直接AnnotationMappingInfoをシステム設定クラスConfigurationに渡すことで、
シート名を設定するアノテーション @XlsSheet(name="<シート名>")
の値を動的に書き換えることが容易にできるようになります。
1// XmlBuilder.createXXX() メソッドを簡単に呼ぶために、static import します。
2import static com.gh.mygreen.xlsmapper.xml.XmlBuilder.*;
3
4public void sample() {
5
6 AnnotationMappingInfo annotationMapping = createXml()
7 .classInfo(createClass(SimpleSheet.class)
8 .override(true) // アノテーションを差分だけ反映する設定を有効にします。
9 .annotation(createAnnotation(XlsSheet.class)
10 .attribute("name", "サンプル")
11 .buildAnnotation())
12 .buildClass())
13 .buildXml();
14
15 // システム設定のConfirgurationに直接渡すこともできます。
16 XlsMapper xlsMapper = new XlsMapper();
17 xlsMapper.getConfiguration.setAnnotationMapping(annotaionMapping);
18
19}