55.2. アノテーション
作成されたアノテーションにより、モデルのさまざまな概念を次のように POJO にマップできます。
- レコードのタイプ (CSV、キーと値のペア (FIX メッセージなど)、固定長など)、
- リンク (別のオブジェクトにあるオブジェクトをリンクする)、
- DataField とそのプロパティー (int、type、…)、
- KeyValuePairField (FIX 財務メッセージにあるようなキー = 値形式の場合)、
- セクション (ヘッダー、本文、およびフッターセクションを識別する)、
- OneToMany,
- BindyConverter,
- FormatFactories
このセクションでは、上記について説明します。
55.2.1. 1.CsvRecord
CsvRecord アノテーションは、モデルのルートクラスを識別するために使用されます。レコード = CSV ファイルの 1 行を表し、複数の子モデルクラスにリンクできます。
アノテーション名 | レコードの種類 | レベル |
---|---|---|
CsvRecord | CSV | クラス |
パラメーター名 | タイプ | 必須/任意 | デフォルト値 | Info |
---|---|---|---|---|
separator | String | ✓ | トークンでレコードを分割するために使用される区切り記号 (必須): ',' または ';'、'anything' にすることができます。サポートされている唯一の空白文字はタブ (\t) です。その他の空白文字 (スペース) はサポートされていません。この値は正規表現として解釈されます。正規表現で特別な意味を持つ記号を使用する場合は、'|' の記号であれば、'|' のようにマスクする必要があります。 | |
allowEmptyStream | boolean | false | allowEmptyStream パラメーターは、利用できないストリームを CSV ファイル向けに処理できるようにします。 | |
autospanLine | boolean | false | Last record spans rest of line (オプション): 有効にすると、コメントなどの場合に、最後の列が自動的に行末に広がります。この設定により、その行にすべての文字と区切り文字を含めることができます。 | |
crlf | String | WINDOWS | Character to be used to add a carriage return after each record (オプション): 使用するキャリッジリターン文字を定義できます。上記の 3 つ以外の値を指定すると、入力した値 (カスタム) が CRLF 文字として使用されます。WINDOWS、UNIX、MAC、またはカスタムの 3 つの値を使用できます。 | |
endWithLineBreak | boolean | true | endWithLineBreak パラメーターは、CSV ファイルが改行で終了するかどうかを示します (オプション) | |
generateHeaderColumns | boolean | false | generateHeaderColumns パラメーターを使用すると、列の名前を含むヘッダーを生成した CSV に追加できます | |
isOrdered | boolean | false | 出力でメッセージを並べ替える必要があるかどうかを示します | |
name | String | レコードを説明する名前 (オプション) | ||
quote | String | " | 指定された引用文字で列をマーシャリングするかどうか (オプション): CSV の生成時にフィールドの引用文字を指定できるようにします。このアノテーションは、モデルのルートクラスに関連付けられており、一度宣言する必要があります。 | |
引用 | boolean | false | マーシャリング時に値 (およびヘッダー) を引用符で囲む必要があるかどうかを示します (オプション) | |
quotingEscaped | boolean | false | 引用時に値をエスケープする必要があるかどうかを示します (オプション) | |
removeQuotes | boolean | true | remove quotes パラメーターフラグ。アンマーシャリングで各フィールドの引用符を削除しようとするかどうか。 | |
skipField | boolean | false | skipField パラメーターを使用すると、CSV ファイルのフィールドをスキップできます。一部のフィールドが不要な場合は、スキップできます。 | |
skipFirstLine | boolean | false | skipFirstLine パラメーターを使用すると、CSV ファイルの最初の行をスキップするかどうかを指定できます。この行には、多くの場合、列の定義が含まれています |
ケース 1: separator = ','
CSV レコード内のフィールド分離に使用されるセパレーターは ,
です。
10, J, Pauline, M, XD12345678, Fortis Dynamic 15/15, 2500, USD, 08-01-2009
@CsvRecord( separator = "," ) public Class Order { }
ケース 2: separator = ';'
前のケースと比較して、ここでのセパレーターは ,
の代わり ;
を使用しています。
10; J; Pauline; M; XD12345678; Fortis Dynamic 15/15; 2500; USD; 08-01-2009
@CsvRecord( separator = ";" ) public Class Order { }
ケース 3: separator = '|'
前のケースと比較して、ここでのセパレーターは ;
の代わり |
を使用しています。
10| J| Pauline| M| XD12345678| Fortis Dynamic 15/15| 2500| USD| 08-01-2009
@CsvRecord( separator = "\\|" ) public Class Order { }
ケース 4: separator = '\",\"'
Camel 2.8.2 以前に該当
CSV レコードの解析対象フィールドに ,
または ;
が含まれる場合。これはセパレーターとしても使用されるため、Camel バインドにこのケースの処理方法を伝える別のストラテジーを見つける必要があります。データを含むフィールドをコンマで定義するには、一重引用符または二重引用符を区切り文字として使用します (例: '10', 'Street 10, NY', 'USA' or "10", "Street 10, NY", "USA")。
__ | この場合、行頭または行末にある一重引用符または二重引用符の文字は bindy によって削除されます。 |
"10","J","Pauline"," M","XD12345678","Fortis Dynamic 15,15","2500","USD","08-01-2009"
@CsvRecord( separator = "\",\"" ) public Class Order { }
Bindy は、レコードが一重引用符または二重引用符で囲まれているかどうかを自動的に検出し、CSV からオブジェクトへのアンマーシャリング時にそれらの引用符を自動的に削除します。したがって、セパレーターに引用符を 含めず に、単に以下を実行するだけです。
"10","J","Pauline"," M","XD12345678","Fortis Dynamic 15,15","2500","USD","08-01-2009"
@CsvRecord( separator = "," ) public Class Order { }
Object から CSV にマーシャリングして引用符を使用する場合は、以下に示すように @CsvRecord
の quote
属性を使用して、使用する引用符を指定する必要があることに注意してください。
@CsvRecord( separator = ",", quote = "\"" ) public Class Order { }
ケース 5: separator & skipFirstLine
この機能は、クライアントがファイルの最初の行にデータフィールドの名前を入れる場合に役立ちます。
order id, client id, first name, last name, isin code, instrument name, quantity, currency, date
解析プロセス中にこの最初の行をスキップする必要があることを bindy に通知するには、次の属性を使用します。
@CsvRecord(separator = ",", skipFirstLine = true) public Class Order { }
ケース 6: generateHeaderColumns
生成された CSV の最初の行に追加するには、次のようにアノテーションで属性 generateHeaderColumns を true に設定する必要があります。
@CsvRecord( generateHeaderColumns = true ) public Class Order { }
その結果、アンマーシャリングプロセス中の Bindy は、次のような CSV を生成します。
order id, client id, first name, last name, isin code, instrument name, quantity, currency, date 10, J, Pauline, M, XD12345678, Fortis Dynamic 15/15, 2500, USD, 08-01-2009
ケース 7: carriage return
camel-bindy が実行されるプラットフォームが Windows ではなく、Macintosh または Unix である場合には、次のように crlf プロパティーを変更できます。WINDOWS、UNIX、または MAC の 3 つの値を使用できます。
@CsvRecord(separator = ",", crlf="MAC") public Class Order { }
さらに、何らかの理由で別の行末文字を追加する必要がある場合は、crlf パラメーターを使用して指定できます。次の例では、コンマとそれに続く改行文字で行を終了できます。
@CsvRecord(separator = ",", crlf=",\n") public Class Order { }
ケース 8: isOrdered
モデルから CSV レコードを作成する際に従う順序が、解析時に使用される順序と異なる場合があります。次に、この場合、属性 isOrdered = true
を使用して、DataField アノテーションの属性 position
と組み合わせて指定できます。
@CsvRecord(isOrdered = true) public Class Order { @DataField(pos = 1, position = 11) private int orderNr; @DataField(pos = 2, position = 10) private String clientNr; }
__ |
|
55.2.2. 2.リンク
リンクアノテーションを使用すると、オブジェクトを相互にリンクできます。
アノテーション名 | レコードの種類 | レベル |
---|---|---|
リンク | all | クラスとプロパティー |
パラメーター名 | タイプ | 必須/任意 | デフォルト値 | Info |
---|---|---|---|---|
linkType | LinkType | OneToOne | クラス間の関係を識別するリンクのタイプ |
現在のバージョンでは、1 対 1 の関係のみが許可されています。
例: モデルクラス Client が Order クラスにリンクされている場合には、次のように Order クラスでアノテーション Link を使用します。
プロパティーリンク
@CsvRecord(separator = ",") public class Order { @DataField(pos = 1) private int orderNr; @Link private Client client; }
クラス Client の場合:
クラスリンク
@Link public class Client { }
55.2.3. 3.DataField
DataField アノテーションは、フィールドのプロパティーを定義します。各データフィールドは、レコード内の位置、タイプ (string、int、date など)、およびパターン (任意) によって識別されます。
アノテーション名 | レコードの種類 | レベル |
---|---|---|
DataField | all | プロパティー |
パラメーター名 | タイプ | 必須/任意 | デフォルト値 | Info |
---|---|---|---|---|
pos | int | ✓ | 入力レコード内のデータの位置。1 から開始する必要があります (必須)。位置パラメーターを参照してください。 | |
align | String | R | テキストを右または左に揃えます。値 <tt>R</tt> または <tt>L</tt> を使用します。 | |
clip | boolean | false | 固定長の使用時に許容される長さを超える場合は、フィールド内のデータを切り取ることを示します。 | |
columnName | String |
ヘッダー列の名前 (オプション)。プロパティーの名前をデフォルトとして使用します。 | ||
decimalSeparator | String | BigDecimal 数値で使用する小数点区切り記号 | ||
defaultValue | String | 値が設定されていない場合のフィールドのデフォルト値 | ||
delimiter | String | フィールドが可変長の場合に使用するオプションの区切り文字 | ||
groupingSeparator | String | 123,456.789 などのグループ化された数値にフォーマット/解析する場合に、BigDecimal 数値と併用するグループ化セパレーター。 | ||
impliedDecimalSeparator | boolean | false | 指定された位置に暗黙の小数点があるかどうかを示します | |
長さ | int | 0 | レコードが固定長に設定されている場合のデータブロックの長さ (文字数) | |
lengthPos | int | 0 | このフィールドで必要とされる固定長を定義するレコードのデータフィールドを識別します | |
メソッド | String | このようなカスタマイズを DataField に適用するために呼び出すメソッド名。これは、データフィールド自体のメソッドである必要があります。そうでない場合には、クラスのメソッドの静的な完全修飾名を指定する必要があります。(例: org.apache.camel.dataformat.bindy.csv.BindySimpleCsvFunctionWithExternalMethodTest.replaceToBar の単体テストを参照) | ||
name | String | フィールドの名前 (オプション) | ||
paddingChar | char | レコードが固定長に設定されている場合に埋め込む文字 | ||
pattern | String | Java フォーマッター (例: SimpleDateFormat) がデータの変換に使用するパターン (オプション)。パターンを使用する場合は、バインドデータ形式にロケールを設定することをお勧めします。us などの既知のロケールに設定するか、default を使用してプラットフォームのデフォルトロケールを使用します。 | ||
position | int | 0 | 生成された出力メッセージ内のフィールドの位置 (1 から開始する必要があります)。生成された CSV 内のフィールドの位置 (出力メッセージ) が、入力位置 (pos) と比較して異なる必要がある場合に使用します。pos パラメーターを参照してください。 | |
精度 | int | 0 | 作成される \{@link java.math.BigDecimal} 数値の精度 | |
必須 | boolean | false | フィールドが必須かどうかを示します | |
rounding | String | CEILING | BigDecimal の丸め/スケーリングに使用される丸めモード 値: UP、DOWN、CEILING、FLOOR、HALF_UP、HALF_DOWN、HALF_EVEN、UNNECESSARY (例: Number = 123456.789, Precision = 2, Rounding = CEILING Result : 123456.79) | |
timezone | String | 使用するタイムゾーン。 | ||
trim | boolean | false | 値をトリミングする必要があるかどうかを示します |
ケース 1: pos
このパラメーター/属性は、CSV レコード内のフィールドの位置を表します。
Position
@CsvRecord(separator = ",") public class Order { @DataField(pos = 1) private int orderNr; @DataField(pos = 5) private String isinCode; }
この例でわかるように、位置は 1
から始まりますが、クラス Order では続きは 5
になります。2
から 4
までの数字はクラス Client で定義されています (以下を参照)。
位置は別のモデルクラスで継続する
public class Client { @DataField(pos = 2) private String clientNr; @DataField(pos = 3) private String firstName; @DataField(pos = 4) private String lastName; }
ケース 2: pattern
パターンを使用すると、データの形式を強化または検証できます
Pattern
@CsvRecord(separator = ",") public class Order { @DataField(pos = 1) private int orderNr; @DataField(pos = 5) private String isinCode; @DataField(name = "Name", pos = 6) private String instrumentName; @DataField(pos = 7, precision = 2) private BigDecimal amount; @DataField(pos = 8) private String currency; // pattern used during parsing or when the date is created @DataField(pos = 9, pattern = "dd-MM-yyyy") private Date orderDate; }
ケース 3: precision
精度は、数値の小数部分を定義する場合に役立ちます。
精度
@CsvRecord(separator = ",") public class Order { @DataField(pos = 1) private int orderNr; @Link private Client client; @DataField(pos = 5) private String isinCode; @DataField(name = "Name", pos = 6) private String instrumentName; @DataField(pos = 7, precision = 2) private BigDecimal amount; @DataField(pos = 8) private String currency; @DataField(pos = 9, pattern = "dd-MM-yyyy") private Date orderDate; }
ケース 4: 出力で位置が異なる
position 属性は、生成された CSV レコードにフィールドを配置する方法を bindy に通知します。デフォルトでは、使用される位置は属性 pos
で定義された位置に対応します。位置が異なる場合 (つまり、マーシャリングとアンマーシャリングを比較する非対称プロセスがあることを意味します)、position
を使用してこれを指定できます。
以下に例を示します。
出力位置が異なる
@CsvRecord(separator = ",", isOrdered = true) public class Order { // Positions of the fields start from 1 and not from 0 @DataField(pos = 1, position = 11) private int orderNr; @DataField(pos = 2, position = 10) private String clientNr; @DataField(pos = 3, position = 9) private String firstName; @DataField(pos = 4, position = 8) private String lastName; @DataField(pos = 5, position = 7) private String instrumentCode; @DataField(pos = 6, position = 6) private String instrumentNumber; }
アノテーション @DataField
のこの属性は、アノテーション @CsvRecord
の属性 isOrdered = true
と組み合わせて使用する必要があります。
ケース 5: 必須
フィールドが必須の場合は、required
属性を true に設定して使用します。
必須
@CsvRecord(separator = ",") public class Order { @DataField(pos = 1) private int orderNr; @DataField(pos = 2, required = true) private String clientNr; @DataField(pos = 3, required = true) private String firstName; @DataField(pos = 4, required = true) private String lastName; }
このフィールドがレコードに存在しない場合には、パーサーにより次の情報を含めてエラーが報告されます。
Some fields are missing (optional or mandatory), line :
ケース 6: trim
フィールドの先頭および/または末尾にスペースがあり、処理する前に削除する必要がある場合は、trim
属性を true に設定してください。
Trim
@CsvRecord(separator = ",") public class Order { @DataField(pos = 1, trim = true) private int orderNr; @DataField(pos = 2, trim = true) private Integer clientNr; @DataField(pos = 3, required = true) private String firstName; @DataField(pos = 4) private String lastName; }
ケース 7: defaultValue
フィールドが定義されていない場合は、defaultValue
属性で示される値が使用されます。
デフォルト値
@CsvRecord(separator = ",") public class Order { @DataField(pos = 1) private int orderNr; @DataField(pos = 2) private Integer clientNr; @DataField(pos = 3, required = true) private String firstName; @DataField(pos = 4, defaultValue = "Barin") private String lastName; }
ケース 8: columnName
@CsvRecord
にアノテーション generateHeaderColumns = true
がある場合にのみ、プロパティーの列名を指定します。
列名
@CsvRecord(separator = ",", generateHeaderColumns = true) public class Order { @DataField(pos = 1) private int orderNr; @DataField(pos = 5, columnName = "ISIN") private String isinCode; @DataField(name = "Name", pos = 6) private String instrumentName; }
この属性は、オプションのフィールドにのみ適用されます。
55.2.4. 4.FixedLengthRecord
FixedLengthRecord アノテーションは、モデルのルートクラスを識別するために使用されます。これは、レコード = 固定長 (文字数) でフォーマットされたデータを含むファイル/メッセージの行を表し、複数の子モデルクラスにリンクできます。フィールドのデータは右または左に位置合わせできるため、この形式は少し特殊です。
データのサイズがフィールドの長さを完全に満たしていない場合は、埋め込み文字を追加できます。
アノテーション名 | レコードの種類 | レベル |
---|---|---|
FixedLengthRecord | 固定: | クラス |
パラメーター名 | タイプ | 必須/任意 | デフォルト値 | Info |
---|---|---|---|---|
countGrapheme | boolean | false | 文字数のカウント方法を示します | |
crlf | String | WINDOWS | 各レコードの後に改行を追加するために使用する文字 (オプション)。使用可能な値: WINDOWS、UNIX、MAC、またはカスタム。このオプションはマーシャリング中にのみ使用されますが、アンマーシャリングでは、eol がカスタマイズされていない限り、JDK が提供するシステムのデフォルトの行区切り文字が使用されます。 | |
eol | String | アンマーシャリング中に各レコードの後ろの行末を考慮する処理に使用される文字 (オプション、デフォルト: "" で、他の行区切り文字が指定されていない場合にデフォルトの JDK が提供する行区切り文字を使用できるようにします)。このオプションは、アンマーシャリング中にのみ使用されます。他の値が指定されていない限り、マーシャリング時に "WINDOWS" として、システムのデフォルトで提供される行区切り文字を使用します。 | ||
footer | クラス | void | このタイプのレコードでは、ファイルの最後に単一のフッターレコードが続く可能性があることを指定します。 | |
header | Class | void | このタイプのレコードでは、ファイルの先頭に単一のヘッダーレコードがある可能性があることを指定します。 | |
ignoreMissingChars | boolean | false | 短すぎる行を無視するかどうかを示します | |
ignoreTrailingChars | boolean | false | アンマーシャリング/解析時に、最後にマップされたフィールドを超える文字を無視できることを示します。このアノテーションは、モデルのルートクラスに関連付けられており、一度宣言する必要があります。 | |
長さ | int | 0 | レコードの固定長 (文字数)。これは、レコードが常に \{#paddingChar ()} でパディングされることを意味します | |
name | String | レコードを説明する名前 (オプション) | ||
paddingChar | char | パディングする文字。 | ||
skipFooter | boolean | false | フッターレコードのマーシャリング/アンマーシャリングをスキップするようにデータ形式を設定します。プライマリーレコードでこのパラメーターを設定します (たとえば、ヘッダーやフッターではありません)。 | |
skipHeader | boolean | false | ヘッダーレコードのマーシャリング/アンマーシャリングをスキップするようにデータ形式を設定します。プライマリーレコードでこのパラメーターを設定します (たとえば、ヘッダーやフッターではありません)。 |
レコードは、ヘッダー/フッターと、プライマリーの固定長レコードを両方に指定できません。
ケース 1: 単純な固定長レコード
この単純な例は、固定メッセージを解析/フォーマットするモデル設計方法を示しています
10A9PaulineMISINXD12345678BUYShare2500.45USD01-08-2009
Fixed-simple
@FixedLengthRecord(length=54, paddingChar=' ') public static class Order { @DataField(pos = 1, length=2) private int orderNr; @DataField(pos = 3, length=2) private String clientNr; @DataField(pos = 5, length=7) private String firstName; @DataField(pos = 12, length=1, align="L") private String lastName; @DataField(pos = 13, length=4) private String instrumentCode; @DataField(pos = 17, length=10) private String instrumentNumber; @DataField(pos = 27, length=3) private String orderType; @DataField(pos = 30, length=5) private String instrumentType; @DataField(pos = 35, precision = 2, length=7) private BigDecimal amount; @DataField(pos = 42, length=3) private String currency; @DataField(pos = 45, length=10, pattern = "dd-MM-yyyy") private Date orderDate; }
ケース 2: アラインメントとパディングのある固定長レコード
こちらの詳細な例は、フィールドの配置を定義する方法と、ここで ' '
であるパディング文字を割り当てる方法を示しています。
10A9 PaulineM ISINXD12345678BUYShare2500.45USD01-08-2009
Fixed-padding-align
@FixedLengthRecord(length=60, paddingChar=' ') public static class Order { @DataField(pos = 1, length=2) private int orderNr; @DataField(pos = 3, length=2) private String clientNr; @DataField(pos = 5, length=9) private String firstName; @DataField(pos = 14, length=5, align="L") // align text to the LEFT zone of the block private String lastName; @DataField(pos = 19, length=4) private String instrumentCode; @DataField(pos = 23, length=10) private String instrumentNumber; @DataField(pos = 33, length=3) private String orderType; @DataField(pos = 36, length=5) private String instrumentType; @DataField(pos = 41, precision = 2, length=7) private BigDecimal amount; @DataField(pos = 48, length=3) private String currency; @DataField(pos = 51, length=10, pattern = "dd-MM-yyyy") private Date orderDate; }
ケース 3: フィールドパディング
' ' の代わりに '0' をパディングする数値形式があるため、レコードに定義されたデフォルトのパディングをフィールドに適用できない場合があります。この場合、モデルで @DataField
の属性 paddingChar
を使用して、この値を設定できます。
10A9 PaulineM ISINXD12345678BUYShare000002500.45USD01-08-2009
Fixed-padding-field
@FixedLengthRecord(length = 65, paddingChar = ' ') public static class Order { @DataField(pos = 1, length = 2) private int orderNr; @DataField(pos = 3, length = 2) private String clientNr; @DataField(pos = 5, length = 9) private String firstName; @DataField(pos = 14, length = 5, align = "L") private String lastName; @DataField(pos = 19, length = 4) private String instrumentCode; @DataField(pos = 23, length = 10) private String instrumentNumber; @DataField(pos = 33, length = 3) private String orderType; @DataField(pos = 36, length = 5) private String instrumentType; @DataField(pos = 41, precision = 2, length = 12, paddingChar = '0') private BigDecimal amount; @DataField(pos = 53, length = 3) private String currency; @DataField(pos = 56, length = 10, pattern = "dd-MM-yyyy") private Date orderDate; }
ケース 4: 区切り文字付きの固定長レコード
固定長レコードでは、レコード内のコンテンツが区切られている場合があります。次の例では、firstName フィールドと lastName フィールドが ^
文字で区切られています。
10A9Pauline^M^ISINXD12345678BUYShare000002500.45USD01-08-2009
Fixed-delimited
@FixedLengthRecord public static class Order { @DataField(pos = 1, length = 2) private int orderNr; @DataField(pos = 2, length = 2) private String clientNr; @DataField(pos = 3, delimiter = "^") private String firstName; @DataField(pos = 4, delimiter = "^") private String lastName; @DataField(pos = 5, length = 4) private String instrumentCode; @DataField(pos = 6, length = 10) private String instrumentNumber; @DataField(pos = 7, length = 3) private String orderType; @DataField(pos = 8, length = 5) private String instrumentType; @DataField(pos = 9, precision = 2, length = 12, paddingChar = '0') private BigDecimal amount; @DataField(pos = 10, length = 3) private String currency; @DataField(pos = 11, length = 10, pattern = "dd-MM-yyyy") private Date orderDate; }
固定長レコードの pos
値は、オプションで、正確な列番号の代わりに序数の連続した値を使用して定義できます。
ケース 5: レコード定義フィールド長の固定長レコード
固定長レコードには、同じレコード内の別のフィールドで必要とされる長さを定義するフィールドが含まれる場合があります。次の例では、instrumentNumber
フィールド値の長さは、レコード内の instrumentNumberLen
フィールドの値によって定義されます。
10A9Pauline^M^ISIN10XD12345678BUYShare000002500.45USD01-08-2009
Fixed-delimited
@FixedLengthRecord public static class Order { @DataField(pos = 1, length = 2) private int orderNr; @DataField(pos = 2, length = 2) private String clientNr; @DataField(pos = 3, delimiter = "^") private String firstName; @DataField(pos = 4, delimiter = "^") private String lastName; @DataField(pos = 5, length = 4) private String instrumentCode; @DataField(pos = 6, length = 2, align = "R", paddingChar = '0') private int instrumentNumberLen; @DataField(pos = 7, lengthPos=6) private String instrumentNumber; @DataField(pos = 8, length = 3) private String orderType; @DataField(pos = 9, length = 5) private String instrumentType; @DataField(pos = 10, precision = 2, length = 12, paddingChar = '0') private BigDecimal amount; @DataField(pos = 11, length = 3) private String currency; @DataField(pos = 12, length = 10, pattern = "dd-MM-yyyy") private Date orderDate; }
ケース 6: ヘッダーとフッター付きの固定長レコード
Bindy は、モデルの一部として設定されている固定長のヘッダーおよびフッターレコードを検出します。ただし、アノテーション付きのクラスが、プライマリー @FixedLengthRecord
クラスと同じパッケージに存在するか、設定されたスキャンパッケージの 1 つに含まれている必要があります。次のテキストは、ヘッダーレコードとフッターレコードで囲まれた 2 つの固定長レコードを示しています。
101-08-2009 10A9 PaulineM ISINXD12345678BUYShare000002500.45USD01-08-2009 10A9 RichN ISINXD12345678BUYShare000002700.45USD01-08-2009 9000000002
Fixed-header-and-footer-main-class
@FixedLengthRecord(header = OrderHeader.class, footer = OrderFooter.class) public class Order { @DataField(pos = 1, length = 2) private int orderNr; @DataField(pos = 2, length = 2) private String clientNr; @DataField(pos = 3, length = 9) private String firstName; @DataField(pos = 4, length = 5, align = "L") private String lastName; @DataField(pos = 5, length = 4) private String instrumentCode; @DataField(pos = 6, length = 10) private String instrumentNumber; @DataField(pos = 7, length = 3) private String orderType; @DataField(pos = 8, length = 5) private String instrumentType; @DataField(pos = 9, precision = 2, length = 12, paddingChar = '0') private BigDecimal amount; @DataField(pos = 10, length = 3) private String currency; @DataField(pos = 11, length = 10, pattern = "dd-MM-yyyy") private Date orderDate; } @FixedLengthRecord public class OrderHeader { @DataField(pos = 1, length = 1) private int recordType = 1; @DataField(pos = 2, length = 10, pattern = "dd-MM-yyyy") private Date recordDate; } @FixedLengthRecord public class OrderFooter { @DataField(pos = 1, length = 1) private int recordType = 9; @DataField(pos = 2, length = 9, align = "R", paddingChar = '0') private int numberOfRecordsInTheFile; }
ケース 7: 固定長レコードの解析時にコンテンツをスキップする
ターゲットユースケースに必要以上の情報を含む、固定長レコードを提供するシステムと統合するのが一般的です。この状況では、不要なフィールドの宣言と解析をスキップすると便利です。これに対応するために、次に宣言されたフィールドの pos
値が最後に解析されたフィールドのカーソル位置を超えている場合には、Bindy により、レコード内で次にマップされたフィールドに移動されます。対象のフィールドに (順序値ではなく) 絶対位置を使用すると、Bindy
は 2 つのフィールド間のコンテンツをスキップします。
同様に、先のフィールドに対象となるコンテンツがない場合があります。この場合には、@FixedLengthRecord
宣言で ignoreTrailingChars
プロパティーを設定して、最後にマップされたフィールド以降のすべての解析をスキップするように Bindy に指示できます。
@FixedLengthRecord(ignoreTrailingChars = true) public static class Order { @DataField(pos = 1, length = 2) private int orderNr; @DataField(pos = 3, length = 2) private String clientNr; // any characters that appear beyond the last mapped field will be ignored }
55.2.5. 5.メッセージ
Message アノテーションは、キーと値のペアフィールドを含むモデルのクラスを識別するために使用されます。この種の形式は、主に Financial Exchange Protocol Messages (FIX) で使用されます。いずれの場合も、このアノテーションは、データがキーによって識別される他の形式に使用できます。キーペアの値は、区切り記号で互いに区切られます。区切り文字には、タブ区切り記号 (Unicode 表現: \u0009
) または見出しの開始 (Unicode 表現: \u0001
) などの特殊文字を使用できます。
FIX メッセージを操作するには、モデルに、Order クラスである可能性があるルートメッセージクラスにリンクされた Header クラスと Trailer クラスが含まれている必要があります。これは必須ではありませんが、camel-bindy を、quickFix プロジェクトに基づく修正ゲートウェイである camel-fix と組み合わせて使用する場合に非常に役立ちます。
アノテーション名 | レコードの種類 | レベル |
---|---|---|
メッセージ | キーと値のペア。 | Class |
パラメーター名 | タイプ | 必須/任意 | デフォルト値 | Info |
---|---|---|---|---|
keyValuePairSeparator | String | ✓ | キーと値のペアの区切り文字は、キーから値を分割するために使用されます (必須)。'\u0001'、'\u0009'、'#', または 'anything' を指定できます。 | |
pairSeparator | String | ✓ | キーと値のペアをトークンに分割するために使用されるペアの区切り文字 (必須)。'='、';'、または 'anything' を指定できます。 | |
crlf | String | WINDOWS | 各レコードの後に改行を追加するために使用する文字 (オプション)。使用可能な値 = WINDOWS、UNIX、MAC、またはカスタム。上記の 3 つ以外の値を指定すると、入力した値 (カスタム) が CRLF 文字として使用されます。 | |
isOrdered | boolean | false | 出力でメッセージを並べ替える必要があるかどうかを示します。このアノテーションは、モデルのメッセージクラスに関連付けられており、一度宣言する必要があります。 | |
name | String | メッセージを説明する名前 (オプション) | ||
type | String | FIX | type は、メッセージのタイプを定義するために使用されます (FIX、EMX など) (オプション) | |
version | String | 4.1 | version は、メッセージのバージョンを定義します (4.1 など) (オプション) |
ケース 1: separator = 'u0001'
FIX メッセージでキーと値のペアフィールドを分離するために使用される区切り文字は、ASCII 01
文字または Unicode 形式の \u0001
です。Java ランタイムエラーを回避するには、この文字をもう一度エスケープする必要があります。以下は例です。
8=FIX.4.1 9=20 34=1 35=0 49=INVMGR 56=BRKR 1=BE.CHM.001 11=CHM0001-01 22=4 ...
およびアノテーションの使用方法:
FIX - メッセージ
@Message(keyValuePairSeparator = "=", pairSeparator = "\u0001", type="FIX", version="4.1") public class Order { }
テストケースを見る
タブなどの ASCII 文字は、WIKI ページでは表示できません。したがって、camel-bindy のテストケースを見て、FIX メッセージ (https://github.com/apache/camel/blob/main/components/camel-bindy/src/test/data/fix/fix.txt) および Order、Trailer、Header クラス (https://github.com/apache/camel/blob/main/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/model/fix/simple/Order.java) が実際にどのように見えるかを確認してください。
55.2.6. 6.KeyValuePairField
KeyValuePairField アノテーションは、キーと値のペアフィールドのプロパティーを定義します。各 KeyValuePairField は、タグ (= キー) とそれに関連付けられた値、タイプ (文字列、整数、日付など)、オプションのパターン、およびフィールドが必須かどうかによって識別されます。
アノテーション名 | レコードの種類 | レベル |
---|---|---|
KeyValuePairField | キーと値のペア - FIX | プロパティー |
パラメーター名 | タイプ | 必須/任意 | デフォルト値 | Info |
---|---|---|---|---|
tag | int | ✓ | メッセージ内のフィールドを識別するタグ (必須) - 一意である必要があります | |
impliedDecimalSeparator | boolean | false | <b>Camel 2.11:</b> 指定された位置に暗黙の小数点があるかどうかを示します | |
name | String | フィールドの名前 (オプション) | ||
pattern | String | フォーマッターがデータの変換に使用するパターン (オプション) | ||
position | int | 0 | 生成されたメッセージ内のフィールドの位置 - FIX メッセージ内のキー/タグの位置が異なる必要がある場合に使用する必要があります | |
精度 | int | 0 | 作成する BigDecimal 数値の精度 | |
必須 | boolean | false | フィールドが必須かどうかを示します | |
timezone | String | 使用するタイムゾーン。 |
ケース 1: tag
このパラメーターは、メッセージ内のフィールドのキーを表します。
FIX メッセージ - タグ
@Message(keyValuePairSeparator = "=", pairSeparator = "\u0001", type="FIX", version="4.1") public class Order { @Link Header header; @Link Trailer trailer; @KeyValuePairField(tag = 1) // Client reference private String Account; @KeyValuePairField(tag = 11) // Order reference private String ClOrdId; @KeyValuePairField(tag = 22) // Fund ID type (Sedol, ISIN, ...) private String IDSource; @KeyValuePairField(tag = 48) // Fund code private String SecurityId; @KeyValuePairField(tag = 54) // Movement type ( 1 = Buy, 2 = sell) private String Side; @KeyValuePairField(tag = 58) // Free text private String Text; }
ケース 2: 出力での別の位置
FIX メッセージに入れるタグ/キーを事前定義された順序に従ってソートする必要がある場合は、アノテーション @KeyValuePairField
の属性 position
を使用します。
FIX メッセージ - タグ - 並べ替え
@Message(keyValuePairSeparator = "=", pairSeparator = "\\u0001", type = "FIX", version = "4.1", isOrdered = true) public class Order { @Link Header header; @Link Trailer trailer; @KeyValuePairField(tag = 1, position = 1) // Client reference private String account; @KeyValuePairField(tag = 11, position = 3) // Order reference private String clOrdId; }
55.2.7. 7.セクション
固定長レコードの FIX メッセージでは、情報の表現にさまざまなセクション (ヘッダー、ボディ、およびセクション) があるのが一般的です。アノテーション @Section
の目的は、モデルのどのクラスがヘッダー (= セクション 1)、ボディ (= セクション 2)、およびフッター (= セクション 3) を表しているかを bindy に通知することです。
このアノテーションには、1 つの属性/パラメーターのみが存在します。
アノテーション名 | レコードの種類 | レベル |
---|---|---|
セクション | FIX | Class |
パラメーター名 | タイプ | 必須/任意 | デフォルト値 | Info |
---|---|---|---|---|
number | int | ✓ | セクション番号 |
ケース 1: セクション
ヘッダーセクションの定義:
FIX メッセージ - セクション - ヘッダー
@Section(number = 1) public class Header { @KeyValuePairField(tag = 8, position = 1) // Message Header private String beginString; @KeyValuePairField(tag = 9, position = 2) // Checksum private int bodyLength; }
本文セクションの定義:
FIX メッセージ - セクション - 本文
@Section(number = 2) @Message(keyValuePairSeparator = "=", pairSeparator = "\\u0001", type = "FIX", version = "4.1", isOrdered = true) public class Order { @Link Header header; @Link Trailer trailer; @KeyValuePairField(tag = 1, position = 1) // Client reference private String account; @KeyValuePairField(tag = 11, position = 3) // Order reference private String clOrdId;
フッターセクションの定義:
FIX メッセージ - セクション - フッター
@Section(number = 3) public class Trailer { @KeyValuePairField(tag = 10, position = 1) // CheckSum private int checkSum; public int getCheckSum() { return checkSum; }
55.2.8. 8.OneToMany
アノテーション @OneToMany
の目的は、POJO クラスで定義された List<?>
フィールドを操作できるようにすること、または反復グループを含むレコードから操作できるようにすることです。
OneToMany の制限事項
bindy の 1 対多では、複数レベルの階層で繰り返しが定義されている場合に処理できない点に注意してください。
OneToMany の関係は、次の場合にのみ機能します。
- 反復グループ (= タグ/キーのグループ) を含む FIX メッセージの読み取り
- 反復データを含む CSV の生成
アノテーション名 | レコードの種類 | レベル |
---|---|---|
OneToMany | all | プロパティー |
パラメーター名 | タイプ | 必須/任意 | デフォルト値 | Info |
---|---|---|---|---|
mappedTo | String | List<Type of the Class> の型に関連付けられたクラス名 |
ケース 1: 反復データで CSV を生成する
必要な CSV 出力は次のとおりです。
Claus,Ibsen,Camel in Action 1,2010,35 Claus,Ibsen,Camel in Action 2,2012,35 Claus,Ibsen,Camel in Action 3,2013,35 Claus,Ibsen,Camel in Action 4,2014,35
反復データは書籍のタイトルとその発行日に関するものですが、姓名と年齢は一般的であり、これをモデル化するために使用されるクラスです。Author クラスには、書籍リストが含まれています。
反復データを含む CSV を生成する
@CsvRecord(separator=",") public class Author { @DataField(pos = 1) private String firstName; @DataField(pos = 2) private String lastName; @OneToMany private List<Book> books; @DataField(pos = 5) private String Age; } public class Book { @DataField(pos = 3) private String title; @DataField(pos = 4) private String year; }
ケース 2: タグ/キーのグループを含む FIX メッセージの読み取り
モデルで処理するメッセージは次のとおりです。
8=FIX 4.19=2034=135=049=INVMGR56=BRKR 1=BE.CHM.00111=CHM0001-0158=this is a camel - bindy test 22=448=BE000124567854=1 22=548=BE000987654354=2 22=648=BE000999999954=3 10=220
タグ 22、48、および 54 が繰り返されます。
およびコード:
タグ/キーのグループを含む FIX メッセージの読み取り
public class Order { @Link Header header; @Link Trailer trailer; @KeyValuePairField(tag = 1) // Client reference private String account; @KeyValuePairField(tag = 11) // Order reference private String clOrdId; @KeyValuePairField(tag = 58) // Free text private String text; @OneToMany(mappedTo = "org.apache.camel.dataformat.bindy.model.fix.complex.onetomany.Security") List<Security> securities; } public class Security { @KeyValuePairField(tag = 22) // Fund ID type (Sedol, ISIN, ...) private String idSource; @KeyValuePairField(tag = 48) // Fund code private String securityCode; @KeyValuePairField(tag = 54) // Movement type ( 1 = Buy, 2 = sell) private String side; }
55.2.9. 9.BindyConverter
アノテーション @BindyConverter
の目的は、フィールドレベルで使用されるコンバーターを定義することです。提供されたクラスは、Format インターフェイスを実装する必要があります。
@FixedLengthRecord(length = 10, paddingChar = ' ') public static class DataModel { @DataField(pos = 1, length = 10, trim = true) @BindyConverter(CustomConverter.class) public String field1; } public static class CustomConverter implements Format<String> { @Override public String format(String object) throws Exception { return (new StringBuilder(object)).reverse().toString(); } @Override public String parse(String string) throws Exception { return (new StringBuilder(string)).reverse().toString(); } }
55.2.10. 10.FormatFactories
アノテーション @FormatFactories
の目的は、一連のコンバーターをレコードレベルで定義することです。提供されるクラスは、FormatFactoryInterface
インターフェイスを実装する必要があります。
@CsvRecord(separator = ",") @FormatFactories({OrderNumberFormatFactory.class}) public static class Order { @DataField(pos = 1) private OrderNumber orderNr; @DataField(pos = 2) private String firstName; } public static class OrderNumber { private int orderNr; public static OrderNumber ofString(String orderNumber) { OrderNumber result = new OrderNumber(); result.orderNr = Integer.valueOf(orderNumber); return result; } } public static class OrderNumberFormatFactory extends AbstractFormatFactory { { supportedClasses.add(OrderNumber.class); } @Override public Format<?> build(FormattingOptions formattingOptions) { return new Format<OrderNumber>() { @Override public String format(OrderNumber object) throws Exception { return String.valueOf(object.orderNr); } @Override public OrderNumber parse(String string) throws Exception { return OrderNumber.ofString(string); } }; } }