搜索

17.3. 注解

download PDF

创建的注解允许将您的模型的不同概念映射到 POJO,如下所示:

  • 记录类型(CSV、键值对(如 FIX 消息)、固定长度 …​)
  • 链接(链接另一个对象中的对象)
  • DataField 及其属性(int, type, …​),
  • KeyValuePairField (用于 key = FIX 财务消息一样的值格式),
  • 部分(要识别标头、正文和页脚部分),
  • OneToMany,
  • BindyConverter,
  • FormatFactories

本节将描述它们。

17.3.1. 1.CsvRecord

CsvRecord 注解用于识别模型的根类。它表示记录 = "CSV 文件的行",并可链接到多个子模型类。

注解名称记录类型级别

CsvRecord

CSV

参数名称类型必填默认值info

分隔符

字符串

 

用于在令牌中分割记录的分隔符(必需)- 可以是 ',' 或 ';' 或 'anything'。唯一支持的空格字符是 tab (\t)。不支持其他空格字符(空格)。这个值被解释为正则表达式。如果要使用在正则表达式中有一个特殊含义,例如 '|' 符号,则必须屏蔽它,如 '|'。

allowEmptyStream

布尔值

 

false

allowEmptyStream 参数将允许 prcoess 的 CSV 文件不可避免的流。

autospanLine

布尔值

 

false

最后一条记录跨越其余行(可选)- 如果启用,则最后一列会自动跨越到行尾,例如,如果其注释,则允许行包含所有字符,也是分隔符 char。

crlf

字符串

 

WINDOWS

要在每个记录后添加回车符(可选)- 允许使用回车字符。如果您指定了之前列出的三个值,则您输入的值(自定义)将用作 CRLF 字符。可以使用三个值:WINDOWS、UNIX、MAC 或 custom。

endWithLineBreak

布尔值

 

true

如果 CSV 文件以换行符或未结束(可选)

generateHeaderColumns

布尔值

 

false

generateHeaderColumns 参数允许在 CSV 中添加生成的包含列名称的标头

isOrdered

布尔值

 

false

指明消息是否在输出中排序

name

字符串

  

描述记录的名称(可选)

quote

字符串

 

"

是否使用给定的引号字符(可选)- 在生成 CSV 时指定字段的引号字符。此注释与模型的根类关联,必须声明一次。

引用

布尔值

 

false

指明在 marshaling (可选)时是否必须用引号括起值(和标头)

quotingEscaped

布尔值

 

false

指明在引用时是否必须转义值(可选)

removeQuotes

布尔值

 

true

如果 unmarshalling 应该尝试删除每个字段的引号,则 remove quotes 参数标志

skipField

布尔值

 

false

skipField 参数将允许跳过 CSV 文件的字段。如果某些字段不需要,可以跳过它们。

skipFirstLine

布尔值

 

false

skipFirstLine 参数将允许跳过或不是 CSV 文件的第一行。此行通常包含列定义

trimLine

布尔值

 

true

在将行解析为数据字段之前,是否修剪每行(stand 和 end)。

case 1 : separator = ','

用于隔离 CSV 记录中字段的分隔符是 :

10, J, Pauline, M, XD12345678, Fortis Dynamic 15/15, 2500, USD, 08-01-2009
@CsvRecord( separator = "," )
public Class Order {

}

case 2 : separator = ';'

与前面的问题单进行比较,这里的分隔符为 ; 而不是 :

10; J; Pauline; M; XD12345678; Fortis Dynamic 15/15; 2500; USD; 08-01-2009
@CsvRecord( separator = ";" )
public Class Order {

}

case 3 : separator = '|'

与前面的问题单进行比较,这里的分隔符为 | 而不是 ; :

10| J| Pauline| M| XD12345678| Fortis Dynamic 15/15| 2500| USD| 08-01-2009
@CsvRecord( separator = "\\|" )
public Class Order {

}

case 4 : separator = '\",\"'

适用于 Camel 2.8.2 或更早版本

当要解析 CSV 记录的字段包含 或 也会用作分隔符时,我们应该找到另一个策略来告知 camel bindy 如何处理这个问题单。 要使用逗号定义包含数据的字段,您可以使用单引号或双引号作为分隔符(例如 : '10', 'Street 10, NY', 'USA' 或 "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 {

}

case 5 : separator 和 skipFirstLine

当客户端想在文件的第一行(数据字段的名称)中时,该功能很有趣:

order id, client id, first name, last name, isin code, instrument name, quantity, currency, date

要通知绑定,必须在解析过程中跳过此第一行,我们使用属性 :

@CsvRecord(separator = ",", skipFirstLine = true)
public Class Order {

}

case 6 : generateHeaderColumns

要在生成的 CSV 第一行中添加,必须在注解中将 generateHeaderColumns 属性设置为 true,如下所示:

@CsvRecord( generateHeaderColumns = true )
public Class Order {

}

因此,在 unmarshaling 过程中 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

case 7 : carriage 返回

如果 camel-bindy 将运行的平台不是 Windows,但 Macintosh 或 Unix,您可以更改类似如下的 crlf 属性。提供三个值:WINDOWS、UNIX 或 MAC

@CsvRecord(separator = ",", crlf="MAC")
public Class Order {

}

另外,如果出于某种原因您需要添加不同的行尾字符,您可以选择使用 crlf 参数指定它。在以下示例中,我们可以使用逗号结束行,后跟换行符:

@CsvRecord(separator = ",", crlf=",\n")
public Class Order {

}

case 8 : isOrdered

有时,在从模型创建 CSV 记录时遵循的顺序与解析过程中使用的顺序不同。然后,在这种情况下,我们可以使用属性 isOrdered = true 来表示这一点与 DataField 注解的属性 位置 相结合。

@CsvRecord(isOrdered = true)
public Class Order {

   @DataField(pos = 1, position = 11)
   private int orderNr;

   @DataField(pos = 2, position = 10)
   private String clientNr;

}
注意

pos 用于解析文件流,而 位置 则用于生成 CSV。

17.3.3. 3.DataField

DataField 注解定义字段的属性。每个 datafield 都由记录中的位置、类型(字符串、int、日期、…​)以及可选的模式来标识。

注解名称记录类型级别

DataField

all

属性

参数名称类型必填默认值info

pos

int

 

数据在输入记录中的位置必须从 1 开始(必需)。请参阅 position 参数。

align

字符串

 

R

将文本与右侧或左对齐。使用值 <tt>R</tt> 或 <tt>L</tt>。

Clip

布尔值

 

false

如果在使用固定长度时超过允许的长度,则指示字段中冲突数据。

columnName

字符串

  

标头列的名称(可选)。使用属性的名称作为默认值。仅在 CsvRecordgenerateHeaderColumns = true时才适用

decimalSeparator

字符串

  

与 BigDecimal 号码一起使用的十进制 9 月器

defaultValue

字符串

  

如果没有设置值,则字段的默认值

delimiter

字符串

  

如果字段有变量长度,要使用的可选分隔符

groupingSeparator

字符串

  

当我们想通过组 e.g. 123,456.789 格式化/稀疏的数字时,分组了要与 BigDecimal 号码一起使用的 9 个分组。

impliedDecimalSeparator

布尔值

 

false

指明是否存在代表在指定位置的十进制点

length

int

 

0

如果记录被设置为固定长度,则数据块的长度(字符数)

lengthPos

int

 

0

识别记录中定义此字段预期的固定长度的数据字段

方法

字符串

  

调用的方法名称,以在 DataField 上应用此类自定义。这必须是 datafield 本身上的方法,或者您必须提供类方法的静态完全限定名称,例如:请参阅单元测试 org.apache.camel.dataformat.bindy.csv.BindySimpleCsvFunctionWithExternalMethodTest.replaceToBar

name

字符串

  

字段的名称(可选)

paddingChar

char

  

如果记录被设置为固定长度,则为 char to pad

pattern

字符串

  

Java formatter (示例为SimpleDateFormat)的模式将用于转换数据(可选)。如果使用模式,则建议在 bindy 数据格式上设置区域设置。设置为已知区域设置,如 "us",或使用 "default" 来使用平台默认区域设置。

position

int

 

0

生成输出消息中的字段位置(从 1 开始)。当 CSV 生成的字段的位置(输出消息)中的字段位置与输入位置(pos)不同时,必须使用。请参阅 pos 参数。

精度

int

 

0

要创建的 \{@link java.math.BigDecimal} 数字的精度

required

布尔值

 

false

指明字段是否强制

Rounding

字符串

 

CEILING

Round mode to round/scale a bigDecimal Values : UP, DOWN, CEILING, FLOOR, HALF_UP, HALF_DOWN,HALF_EVEN, UNNECESSARY e.g : Number = 123456.789, Precision = 2, Rounding = CEILING Result: 123.79.

timezone

字符串

  

要使用的时区。

trim

布尔值

 

false

指明值是否应修剪

case 1:pos

这个参数/属性代表 CSV 记录中字段的位置。

position

@CsvRecord(separator = ",")
public class Order {

    @DataField(pos = 1)
    private int orderNr;

    @DataField(pos = 5)
    private String isinCode;

}

如本例中所示,位置从 1 开始,但仍然在类 Order 中从 5 开始。24 的数字在类客户端中定义(请参见此处)。

在另一个模型类中继续位置

public class Client {

    @DataField(pos = 2)
    private String clientNr;

    @DataField(pos = 3)
    private String firstName;

    @DataField(pos = 4)
    private String lastName;
}

case 2:模式

模式允许增强或验证您的数据格式

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;
}

case 3 : 精度

当您想定义数字的十进制部分时,精度很有用。

精度

@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 属性将通知 bindy 如何将字段放在生成的 CSV 记录中。默认情况下,使用的位置对应于通过属性 pos 定义的位置。如果位置不同(这意味着我们有一个 asymetric processus marshaling from unmarshaling),则我们可以使用 位置 来指示这一点。

下面是一个示例:

输出中的位置不同

@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 结合使用。

case 5 : 必需

如果需要字段,只需使用 所需的 属性设为 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 :

case 6 : 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;
}

case 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;
}

case 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;
}

此属性仅适用于可选字段。

17.3.4. 4.FixedLengthRecord

FixedLengthRecord 注解用于识别模型的根类。它代表 record = "文件/message 的行包含数据固定长度(字符数)格式,并可链接到多个子模型类。这个格式是一个具体格式,因为字段的数据可以与右侧或左侧一致。

当数据的大小没有完全填写字段长度时,我们可以添加"本"字符。

注解名称记录类型级别

FixedLengthRecord

已修复

参数名称类型必填默认值info

countGrapheme

布尔值

 

false

指明如何计算收费

crlf

字符串

 

WINDOWS

要在每个记录后添加回车字符(可选)。可能的值有:WINDOWS、UNIX、MAC 或 custom。这个选项仅在 marshalling 期间使用,而 unmarshalling 使用系统默认 JDK 提供的行分隔符,除非自定义 eol。

EOL

字符串

  

字符用于在每个记录后考虑行尾(可选 - default: ""),它可以帮助默认 JDK 提供的行分隔符使用,除非提供了任何其他值。)此选项仅在 unmarshalling 期间使用,其中 marshall 使用系统默认提供的行分隔符作为 "WINDOWS"。

footer

 

void

表示此类型的记录可以跟随文件末尾的单个页脚记录

header

 

void

表示此类型的记录前面可以加上文件开头的单个标头记录

ignoreMissingChars

布尔值

 

false

指明是否忽略太短行

ignoreTrailingChars

布尔值

 

false

表示在 unmarshalling / 解析时会忽略最后一个映射文件之外的字符。此注释与模型的根类关联,必须声明一次。

length

int

 

0

记录的固定长度(字符数)。这意味着,记录将始终是使用 \{#paddingChar ()}'s 持续添加的

name

字符串

  

描述记录的名称(可选)

paddingChar

char

  

使用 char to pad。

skipFooter

布尔值

 

false

配置数据格式,以跳过页脚记录的 marshalling / unmarshalling。在主记录上配置此参数(例如,不是标头或页脚)。

skipHeader

布尔值

 

false

配置数据格式,以跳过标头记录的 marshalling / unmarshalling。在主记录上配置此参数(例如,不是标头或页脚)。

记录不能是标头/页脚和主要固定长度记录。

问题单 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:使用 alignment 和 padding 修复长度记录

此更详细的示例演示了如何定义字段的对齐以及如何分配 padding 字符,该字符为 ' '

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;
}

case 3:字段填充

有时,为记录定义的默认 padding 不能应用于字段,因为我们有一个数字格式,其中我们希望使用 '0' 而不是 ' ' pad。在这种情况下,您可以在模型中使用 @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

固定分隔

@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;
}

可以使用 ordinal, sequential 值而不是精确列号来定义固定长度记录中的 pos 值。

case 5 :带有记录定义字段长度的固定长度记录

有时,固定长度记录可能会包含一个字段,用于定义同一记录中另一个字段的预期长度。在以下示例中,instrumentNumber 字段值的长度由记录中的 instrumentNumberLen 字段的值定义。

10A9Pauline^M^ISIN10XD12345678BUYShare000002500.45USD01-08-2009

固定分隔

@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;
}

case 6:带有标头和页脚的固定长度记录

bindy 将发现作为模型的一部分配置的固定长度标头和页脚记录 - 只要注解的类存在于与主 @FixedLengthRecord 类相同的软件包中,或者在其中一个配置的扫描软件包中。以下文本说明了两个固定长度记录,它们被标头记录和页脚记录括起来。

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;
}

case 7 : 在解析固定长度记录时跳过内容

通常与提供固定长度记录的系统集成,其包含比目标用例所需信息更多的系统。在这种情况下,跳过我们不需要的字段的声明和解析。要接受这一点,Bindy 将跳过记录中的下一个映射字段,如果下一个声明字段的 pos 值不在最后一个解析字段的光标位置。对感兴趣的字段使用绝对 pos 位置(而不是 ordinal 值)会导致 Bindy 在两个字段之间跳过内容。

同样,可能不关注某些字段之外的内容。在这种情况下,您可以通过设置 @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

}

17.3.5. 5.消息

Message 注解用于识别包含键值对字段的模型类。此类格式主要在 financial Exchange Protocol Messages (FIX)中使用。但是,此注解可用于通过密钥标识数据的任何其他格式。密钥对值由分隔符相互分隔,可以是诸如 tab delimitor (unicode representation : \u0009)或标题的开头(unicode representation : \u0001)

注意

要使用 FIX 消息,模型必须包含链接到根消息类的标头和 Trailer 类,可以是 Order 类。这不是强制要求,当您将 camel-bindy 与 camel-fix 结合使用时,这是基于 quickFix 项目的修复网关时,将非常有用。

注解名称记录类型级别

消息

键值对

参数名称类型必填默认值info

keyValuePairSeparator

字符串

 

键值对分隔符用于从其键中分离值(必需)。可以是 '\u0001', '\u0009', '#' 或 'anything'。

pairSeparator

字符串

 

用于在令牌中分割键值对的对(必需)。可以是 '=', ';', 或 'anything'。

crlf

字符串

 

WINDOWS

要在每个记录后添加回车字符(可选)。可能的值 = WINDOWS、UNIX、MAC 或 custom。如果您指定了之前列出的三个值,则您输入的值(自定义)将用作 CRLF 字符。

isOrdered

布尔值

 

false

指明消息是否在输出中排序。此注释与模型的消息类关联,必须声明一次。

name

字符串

  

描述消息的名称(可选)

type

字符串

 

修复

type 用于定义消息的类型(如 FIX、EMX、…​)(可选)

version

字符串

 

4.1

version 定义消息的版本(如 4.1、…​)(可选)

case 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

@Message(keyValuePairSeparator = "=", pairSeparator = "\u0001", type="FIX", version="4.1")
public class Order {

}

查看测试问题单

ASCII 字符,如 tab,…​ 无法显示在 WIKI 页面中。因此,请看一个 camel-bindy 测试案例,来准确查看 FIX 消息是什么样子和 Order,Trailer, Header class (https://github.com/apache/camel/blob/main/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/model/fix/simple/Order.java)。

17.3.6. 6.KeyValuePairField

KeyValuePairField 注解定义键值对字段的属性。每个 KeyValuePairField 都由一个标签(= key)及其关联的值标识,一个类型(字符串、int、date、…​)、可选模式以及是否需要字段。

注解名称记录类型级别

KeyValuePairField

Key Value Pair - FIX

属性

参数名称类型必填默认值info

tag

int

 

标识消息中的字段的标签(必需)- 必须是唯一的

impliedDecimalSeparator

布尔值

 

false

<b>Camel 2.11:</b> 表示在指定位置是否有十进制点

name

字符串

  

字段的名称(可选)

pattern

字符串

  

格式者将用于转换数据的模式(可选)

position

int

 

0

字段在生成的消息中的位置 - 当 FIX 消息中的键/标签的位置必须不同时,必须使用

精度

int

 

0

要创建的 BigDecimal 数量的精度

required

布尔值

 

false

指明字段是否强制

timezone

字符串

  

要使用的时区。

问题单 1:标签

这个参数代表消息中字段的密钥:

FIX message - Tag

@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;
}

case 2:输出中的不同位置

如果我们将放入 FIX 消息中的标签/密钥按照预定义的顺序排序,则使用注释 @KeyValuePairField 的属性 位置

FIX message - Tag - sort

@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;
}

17.3.7. 7.部分

在固定长度记录的 FIX 消息中,通常以信息 : header, body 和 section 表示不同的部分。注释的 @Section 的目的是告知绑定模型中哪个类代表标头(= section 1)、body (= section 2)和页脚(= section 3)

此注释仅存在一个属性/参数。

注解名称记录类型级别

部分

修复

参数名称类型必填默认值info

number

int

 

部分数

问题单 1:部分

header 部分的定义:

FIX message - Section - Header

@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;
}

body 部分的定义:

FIX message - Section - Body

@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;

footer 部分的定义:

FIX message - Section - Footer

@Section(number = 3)
public class Trailer {

    @KeyValuePairField(tag = 10, position = 1)
    // CheckSum
    private int checkSum;

    public int getCheckSum() {
        return checkSum;
    }

17.3.8. 8.OneToMany

注释 @OneToMany 的目的是允许处理 List<?& gt; 字段定义的 POJO 类或包含重复组的记录。

注意

OneToMany
的限制要小心,很多绑定都不允许处理在多个层次上定义的重复。

在以下情况下,关系仅是 WORKS:

  • 读取包含重复组的 FIX 消息(= 标签/密钥组)
  • 生成带有重复数据的 CSV
注解名称记录类型级别

OneToMany

all

属性

参数名称类型必填默认值info

mappedTo

字符串

  

与 Class> 的 List<Type 类型关联的类名称

问题单 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 类包含 Book 的列表。

使用重复数据生成 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;
}

case 2 : Reading FIX message containing group of tags/keys

以下是我们希望在我们的模型中处理的消息:

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;
}

17.3.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();
    }
}

17.3.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);
            }
        };
    }
}
Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

© 2024 Red Hat, Inc.